home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / pc / BOBOLI.ZIP / SRC / BOBOLI.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-06  |  75.6 KB  |  2,244 lines

  1. /* 
  2.   BOBOLI main game executable
  3.   By Mike Hommel
  4.   CSC 404
  5.   compile with DJGPP v2
  6. */
  7. #include "mgraph.h"
  8. #include "umk.h"
  9. #include "timer.h"
  10. #include "mkey.h"
  11. #include "mfont.h"
  12. #include "boboli.h"
  13. #include "guys.h"
  14. #include <stdio.h>
  15. #include "com.h"
  16.  
  17. projectile prj[maxprjctls];
  18. displayrec disp[maxdisplay];
  19. genrec gen[maxgen];
  20. umkset stuff,guypix[numtypes],prjpix,objpix;
  21. scrntype scrn,scrn2;
  22. byte *backgd[2];
  23. byte curpage=0;
  24. byte anim=0;
  25. tileset tiles;
  26. paltype gamepal;
  27. colmat dark;
  28. maprec map;
  29. byte quit=0;
  30. short scrx,scry;
  31. creature guy[maxguys];
  32. playerrec player[numplayers];
  33. centerray guyctr[numtypes],prjctr,objctr;
  34. word randseed1=20; /* for my not-quite-random number generator */
  35. word randseed2=75;
  36. word randnum,randrange;
  37. rect validscreen={0,0,199,199};
  38. byte player_num; /* which of the players is on this computer */
  39. byte twoplayer=1;
  40. byte numcreatures=0;
  41.  
  42. void titles(void)
  43. {
  44.   paltype p;
  45.   memset(p,0,768);
  46.   setpal(p);
  47.   loadPCX("pcx\\title.pcx",p,screen);
  48.   fade_in(0,0,0,p);
  49.   print(318-14*6,192,244,0,"PRESS A KEY...",screen);
  50.   while((keystate(_Q)!=pressed)&&(keystate(_A)!=pressed)&&
  51.      (keystate(_S)!=pressed)&&(keystate(_W)!=pressed));
  52.   clear(0,screen);
  53. }
  54.  
  55. byte intersect(rect s,rect d)
  56. {
  57.   return ((s.x<=d.x2)&&(s.x2>=d.x)&&(s.y<=d.y2)&&
  58.           (s.y2>=d.y)&&(s.x!=s.x2)&&(s.y!=s.y2)&&
  59.           (d.x!=d.x2)&&(d.y!=d.y2));
  60. }
  61.  
  62. word random(word range)
  63. {
  64.   randrange=range;
  65.   asm volatile ("pusha
  66.        movw _randseed2,%ax
  67.        movw _randseed1,%bx
  68.        movw %ax,%si
  69.        movw %bx,%di
  70.        movb %ah,%dl
  71.        movb %al,%ah
  72.        movb %bh,%al
  73.        movb %bl,%bh
  74.        xorb %bl,%bl
  75.        rcrb $1,%dl
  76.        rcrw $1,%ax
  77.        rcrw $1,%bx
  78.        addw %di,%bx
  79.        adcw %si,%ax
  80.        addw $0x62e9,%bx
  81.        adcw $0x3619,%ax
  82.        movw %bx,_randseed2
  83.        movw %ax,_randseed1
  84.        xorw %dx,%dx
  85.        movw _randrange,%cx
  86.        divw %cx
  87.        movw %dx,_randnum
  88.        popa");
  89.   return randnum;
  90. }
  91.  
  92. void gamedelay(void)
  93. {
  94.   asm volatile ("pushw %ax
  95.   1:
  96.        movb _timetick,%al
  97.        cmpb $0,%al
  98.        jz  1b
  99.        popw %ax
  100.        ");
  101.   timetick=0;
  102.   waitretrace();
  103. }
  104.  
  105. void loadctr(char *name,centerray c)
  106. {
  107.   FILE *f;
  108.   f=fopen(name,"rb");
  109.   fread(c,1,sizeof(centerray),f);
  110.   fclose(f);
  111. }
  112.  
  113. void loadtiles(char *name,tileset t)
  114. {
  115.   short i,j,k,x,y;
  116.   paltype p;
  117.   loadPCX(name,p,scrn);
  118.   x=0; y=0;
  119.   for(i=0;i<128;i++) {
  120.     for(j=0;j<16;j++)
  121.       for(k=0;k<16;k++)
  122.         t[i][j+k*16]=scrn[x+j+(y+k)*320];
  123.     x+=16;
  124.     if(x>319) {
  125.       x=0;
  126.       y+=16;
  127.     }
  128.   }
  129. }
  130.  
  131. void loadmap(void)
  132. {
  133.   FILE *f;
  134.   f=fopen("temp.map","rb");
  135.   fread(map,sizeof(maprec),1,f);
  136.   fread(gen,sizeof(genrec)*maxgen,1,f);
  137.   fclose(f);
  138. }
  139.  
  140. void get_input(byte wh)
  141. {
  142.   if(guy[player[wh].who].hp>0) {
  143.     player[wh].command=((keystate(Up)==pressed)||(keystate(Up)==held))*cmd_up+
  144.                        ((keystate(Down)==pressed)||(keystate(Down)==held))*cmd_dn+
  145.                        ((keystate(Left)==pressed)||(keystate(Left)==held))*cmd_lf+
  146.                        ((keystate(Right)==pressed)||(keystate(Right)==held))*cmd_rt+
  147.                        ((keystate(_Q)==pressed)||(keystate(_Q)==held))*cmd_at+
  148.                        (keystate(_A)==pressed)*cmd_drop+
  149.                        (keystate(_S)==pressed)*cmd_next+
  150.                        (keystate(_W)==pressed)*cmd_use;
  151.   } else player[wh].command=0;
  152. }
  153.  
  154. byte addcreature(byte kind,short x,short y,byte dir,byte control)
  155. {
  156.   byte i=0;
  157.   while((i<maxguys)&&(guy[i].kind!=nobody)) i++;
  158.   if(i==maxguys) return 255;
  159.   numcreatures++;
  160.   guy[i].kind=kind;
  161.   guy[i].hp=cd[kind].maxhp;
  162.   guy[i].x=x;
  163.   guy[i].y=y;
  164.   guy[i].z=0;
  165.   guy[i].dz=0;
  166.   guy[i].dir=dir;
  167.   guy[i].timer=0;
  168.   guy[i].doing=do_stand;
  169.   guy[i].frame=0;
  170.   guy[i].control=control;
  171.   guy[i].nearfoe=255;
  172.   guy[i].friend=255;
  173.   guy[i].state=0;
  174.   return i;
  175. }
  176.  
  177. byte addprjctl(byte kind,short x,short y,byte z,byte dir,byte launcher,byte lguy)
  178. {
  179.   byte i=0;
  180.   while((i<maxprjctls)&&(prj[i].kind!=pr_none)) i++;
  181.   if(i==maxprjctls) return 255;
  182.   prj[i].kind=kind;
  183.   prj[i].x=x;
  184.   prj[i].y=y;
  185.   prj[i].z=z;
  186.   prj[i].dir=dir%4;
  187.   prj[i].launchguy=lguy;
  188.   switch(kind) {
  189.     case pr_spark: prj[i].timer=6;
  190.                    prj[i].dx=2-random(5);
  191.                    prj[i].dy=2-random(5);
  192.                    prj[i].dz=0;
  193.                    if(dir==1) prj[i].dz=1;
  194.                    break;
  195.     case pr_golem: prj[i].timer=14;
  196.                    prj[i].dx=0;
  197.                    prj[i].dy=0;
  198.                    prj[i].dz=0;
  199.                    break;
  200.     case pr_flower: prj[i].timer=26;
  201.                    prj[i].dx=0;
  202.                    prj[i].dy=0;
  203.                    prj[i].dz=0;
  204.                    break;
  205.     case pr_shield: prj[i].timer=1;
  206.                     prj[i].dx=0;
  207.                     prj[i].dy=0;
  208.                     prj[i].dz=0;
  209.                     break;
  210.     case pr_smoke: prj[i].timer=12;
  211.                    prj[i].dx=0;
  212.                    prj[i].dy=0;
  213.                    prj[i].dz=2;
  214.                    break;
  215.     case pr_splash: prj[i].timer=35;
  216.                     prj[i].dx=0;
  217.                     prj[i].dy=0;
  218.                     prj[i].dz=0;
  219.                     break;
  220.     case pr_tornado: prj[i].timer=50;
  221.                      prj[i].dx=2*(dir==0)-2*(dir==2);
  222.                      prj[i].dy=2*(dir==1)-2*(dir==3);
  223.                      prj[i].dz=0;
  224.                      break;
  225.     case pr_hsprk: prj[i].timer=6;
  226.                    prj[i].dx=2-random(5);
  227.                    prj[i].dy=2-random(5);
  228.                    prj[i].dz=0;
  229.                    if(dir==1) prj[i].dz=1;
  230.                    break;
  231.     case pr_arrow: prj[i].timer=0;
  232.                    prj[i].dx=7*(prj[i].dir==0)-7*(prj[i].dir==2);
  233.                    prj[i].dy=7*(prj[i].dir==1)-7*(prj[i].dir==3);
  234.                    prj[i].dz=0;
  235.                    if((dir>3)&&(dir<8)) {
  236.                      prj[i].dx+=3*(prj[i].dir==3)-3*(prj[i].dir==1);
  237.                      prj[i].dy+=3*(prj[i].dir==0)-3*(prj[i].dir==2);
  238.                    }
  239.                    if(dir>7) {
  240.                      prj[i].dx+=3*(prj[i].dir==1)-3*(prj[i].dir==3);
  241.                      prj[i].dy+=3*(prj[i].dir==2)-3*(prj[i].dir==0);
  242.                    }
  243.                    break;
  244.     case pr_fball: prj[i].timer=5;
  245.                    prj[i].dx=5*(dir==0)-5*(dir==2);
  246.                    prj[i].dy=5*(dir==1)-5*(dir==3);
  247.                    prj[i].dz=0;
  248.                    break;
  249.     case pr_burst: prj[i].timer=8;
  250.                    prj[i].dx=0;
  251.                    prj[i].dy=0;
  252.                    prj[i].dz=0;
  253.                    break;
  254.     case pr_homing: prj[i].timer=35*5;
  255.                     prj[i].dx=0;
  256.                     prj[i].dy=0;
  257.                     prj[i].dz=0;
  258.                     break;
  259.     case pr_skull: prj[i].timer=70;
  260.                    prj[i].dx=(dir==0)-(dir==2);
  261.                    prj[i].dy=(dir==1)-(dir==3);
  262.                    prj[i].dz=0;
  263.                    break;
  264.     case pr_brightspot: prj[i].timer=10+(z>0)*4;
  265.                         prj[i].dx=0;
  266.                         prj[i].dy=0;
  267.                         prj[i].dz=0;
  268.                         prj[i].z=0;
  269.                         break;
  270.     case pr_slime: prj[i].timer=0;
  271.                    prj[i].dx=4*(dir==0)-4*(dir==2);
  272.                    prj[i].dy=4*(dir==1)-4*(dir==3);
  273.                    prj[i].dz=3;
  274.                    break;
  275.     case pr_splat: prj[i].timer=6;
  276.                    prj[i].dx=0;
  277.                    prj[i].dy=0;
  278.                    prj[i].dz=0;
  279.                    break;
  280.   }
  281.   prj[i].launcher=launcher;
  282.   return i;
  283. }
  284.  
  285.  
  286. void init_player(byte wh)
  287. {
  288.   byte i;
  289.   strcpy(player[wh].name,"JAMUL");
  290.   player[wh].color=19+wh*16;
  291.   player[wh].command=0;
  292.   player[wh].who=addcreature(boboli,32+wh*48+8,32,1,wh);
  293.   player[wh].homex=(32+wh*48)/16;
  294.   player[wh].homey=2;
  295.   map[player[wh].homex+player[wh].homey*mapwidth].object=ob_genrtr;
  296.   for(i=0;i<maxgen;i++) if(gen[i].kind==gn_none) {
  297.     gen[i].kind=gn_boboli;
  298.     gen[i].x=player[wh].homex;
  299.     gen[i].y=player[wh].homey;
  300.     gen[i].hp=1;
  301.     gen[i].frame=1;
  302.     i=maxgen;
  303.   }
  304.   guy[player[wh].who].state|=st_invis;
  305.   guy[player[wh].who].state|=st_invinc;
  306.   guy[player[wh].who].hp=0;
  307.   guy[player[wh].who].friend=wh;
  308.   player[wh].victimkind=255;
  309.   player[wh].strength=1;
  310.   player[wh].speed=1;
  311.   player[wh].intellect=1;
  312.   player[wh].armor=1;
  313.   player[wh].skill=0;
  314.   player[wh].magictimer=1;
  315.   player[wh].selfhptimer=1;
  316.   player[wh].magic=0;
  317.   player[wh].selfhp=0;
  318.   player[wh].realmagic=0;
  319.   player[wh].realselfhp=0;
  320.   player[wh].using=0;
  321.   player[wh].messtimer=0;
  322.   strcpy(player[wh].message,player[wh].name);
  323.   player[wh].inv[0]=it_xbow;
  324.   player[wh].invistimer=0;
  325.   player[wh].invinctimer=0;
  326.   for(i=1;i<6;i++) 
  327.     player[wh].inv[i]=0;
  328. }
  329.  
  330. void init_boboli(void)
  331. {
  332.   byte i;
  333.   __djgpp_nearptr_enable();
  334.   initmg();
  335.   timer_init(FRAMERATE);
  336.   kb_init();
  337.   font_init("misc\\little.fnt");
  338.   gmode(0x13);
  339.   scrn=(scrntype)malloc(64000);
  340.   scrn2=(scrntype)malloc(64000);
  341.   backgd[0]=(byte *)malloc(backgdwidth*backgdheight);
  342.   backgd[1]=(byte *)malloc(backgdwidth*backgdheight);
  343.   mat_load("misc\\dark.mat",dark);
  344.   umk_load("umks\\stuff.umk",stuff);
  345.   umk_load("umks\\boboli.umk",guypix[0]);
  346.   umk_load("umks\\bonehead.umk",guypix[1]);
  347.   umk_load("umks\\glob.umk",guypix[2]);
  348.   umk_load("umks\\golem.umk",guypix[3]);
  349.   umk_load("umks\\orc.umk",guypix[4]);
  350.   umk_load("umks\\mage.umk",guypix[5]);
  351.   umk_load("umks\\prjctls.umk",prjpix);
  352.   umk_load("umks\\objects.umk",objpix);
  353.   loadctr("ctr\\boboli.ctr",guyctr[0]);
  354.   loadctr("ctr\\bonehead.ctr",guyctr[1]);
  355.   loadctr("ctr\\glob.ctr",guyctr[2]);
  356.   loadctr("ctr\\golem.ctr",guyctr[3]);
  357.   loadctr("ctr\\orc.ctr",guyctr[4]);
  358.   loadctr("ctr\\mage.ctr",guyctr[5]);
  359.   loadctr("ctr\\prjctls.ctr",prjctr);
  360.   loadctr("ctr\\objects.ctr",objctr);
  361.   loadtiles("pcx\\tiles.pcx",tiles);
  362.   loadPCX("pcx\\main.pcx",gamepal,scrn2);
  363.   titles();
  364.   setpal(gamepal);
  365.   for(i=0;i<maxguys;i++) guy[i].kind=nobody;
  366.   for(i=0;i<maxprjctls;i++) prj[i].kind=pr_none;
  367.   loadmap();
  368.   init_player(0);
  369.   if(twoplayer) init_player(1);
  370.   addcreature(mage,60*16,54*16,1,255);
  371. }
  372.  
  373. void exit_boboli(void)
  374. {
  375.   kb_exit();
  376.   timer_exit();
  377.   gmode(0x3);
  378.   umk_free(stuff);
  379.   umk_free(prjpix);
  380.   umk_free(objpix);
  381.   umk_free(guypix[0]);
  382.   umk_free(guypix[1]);
  383.   umk_free(guypix[2]);
  384.   free(scrn);
  385.   free(scrn2);
  386.   free(backgd[0]);
  387.   free(backgd[1]);
  388.   while(kbhit()) getch();
  389.   __djgpp_nearptr_disable();
  390. }
  391.  
  392. byte calc_shadows(byte x,byte y)
  393. {
  394.   byte v;
  395.   if(map[x+y*mapwidth].floor>63) return 0; /* no shadows on walls */
  396.   if((map[x+y*mapwidth].floor==1)||(map[x+y*mapwidth].floor==2))
  397.     return 0; /* no shadows on doors */
  398.   if(x==0) {
  399.     if(y==0) return 6;
  400.     else if(map[x+(y-1)*mapwidth].floor>63) return 6;
  401.     else return 2;
  402.   }
  403.   if(y==0) { 
  404.     if(map[x-1+y*mapwidth].floor>63) return 6;
  405.     else return 4;
  406.   }
  407.   if(map[x-1+y*mapwidth].floor>63) {
  408.     if(map[x+(y-1)*mapwidth].floor>63) return 6;
  409.     if(map[x-1+(y-1)*mapwidth].floor>63) return 2;
  410.     else return 1;
  411.   }
  412.   if(map[x+(y-1)*mapwidth].floor>63) {
  413.     if(map[x-1+(y-1)*mapwidth].floor>63) return 4;
  414.     else return 5;
  415.   }
  416.   if(map[x-1+(y-1)*mapwidth].floor>63) return 3;
  417.   return 0;
  418. }
  419.  
  420. long tilesrc,tiledst,tilecaddr;
  421. void tile_shadow(byte x,byte y,colmat c,umkrec u,byte *scr)
  422. {
  423.   tilesrc=(long)u.img;
  424.   tiledst=(long)(scr+x+y*backgdwidth);
  425.   tilecaddr=(long)c;
  426.   asm("pusha
  427.        push %ds
  428.        pop  %es
  429.        movl _tilesrc,%esi
  430.        movl _tiledst,%edi
  431.        movb $16,%dl
  432.        movb $16,%dh
  433.        xorl %eax,%eax
  434.        movl _tilecaddr,%ebx
  435. tshloop1:
  436.        movb %ds:(%esi),%al
  437.        incl %esi
  438.        cmpb $0,%al
  439.        jnz  tshnonzero
  440.        movb %ds:(%esi),%al
  441.        incl %esi
  442.        addl %eax,%edi
  443.        subb %al,%dl
  444.        jnz  tshloop1
  445.        jmp tshlinedone
  446. tshnonzero:
  447.        movb %es:(%edi),%al
  448.        movb %ds:(%ebx,%eax),%al
  449.        movb %al,%es:(%edi)
  450.        incl %edi
  451.        decb %dl
  452.        jnz  tshloop1
  453. tshlinedone:
  454.        decb %dh
  455.        jz   tshdone
  456.        addl $240,%edi
  457.        movb $16,%dl
  458.        jmp  tshloop1
  459. tshdone:
  460.        popa");
  461. }
  462.  
  463. void draw_tile(byte x,byte y,tilerec t,byte *scr)
  464. {
  465.   register byte i;
  466.   for(i=0;i<16;i++) {
  467.     memcpy(&(scr[x+y*backgdwidth]),&(tiles[t.floor][i*16]),16);
  468.     y++;
  469.   }
  470.   y-=16;
  471.   if(t.shadow>0)
  472.     tile_shadow(x,y,dark,stuff[t.shadow-1],scr);
  473. }
  474.  
  475. void draw_map(short x,short y)
  476. {
  477.   byte i,j;
  478.   byte sx,sy;
  479.   sy=16-(y%16);
  480.   for(j=(byte)(y/16);j<(byte)(y/16+14);j++) {
  481.     sx=16-(x%16);
  482.     for(i=(byte)(x/16);i<(byte)(x/16+14);i++) {
  483.       draw_tile(sx,sy,map[i+j*mapwidth],backgd[0]);
  484.       sx+=16;
  485.     }
  486.     sy+=16;
  487.   }
  488.   for(i=16;i<216;i++) 
  489.     memcpy(&(scrn[(i-16)*320]),&(backgd[0][16+i*backgdwidth]),200);
  490.   curpage=0;
  491. }
  492.  
  493. void scrollscr(short dx,short dy,scrntype src,scrntype dst)
  494. {
  495.   long sofs,dofs,amt;
  496.   amt=((256-abs(dx))>>2)+(255-abs(dy))*64+1;
  497.   sofs=(long)src+(dy>0)*(dy*256);
  498.   dofs=(long)dst+(dy<0)*(-dy*256);
  499.   sofs+=(dx>0)*dx;
  500.   dofs+=(dx<0)*(-dx);
  501.   asm("pusha
  502.        pushw %%ds
  503.        popw  %%es
  504.        movl  %0,%%esi
  505.        movl  %1,%%edi
  506.        movl  %2,%%ecx
  507.        rep;  movsl
  508.        popa"::"m" (sofs),"m" (dofs),"m" (amt)); 
  509. }
  510.  
  511. void update_inv(void)
  512. {
  513.   short i,x=212,y=61;
  514.   xfer(211,60,278+32+1,94+32+1,scrn2,scrn);
  515.   for(i=0;i<6;i++) {
  516.     if(player[player_num].inv[i]>it_none) 
  517.       umk_draw(x,y,stuff[7+player[player_num].inv[i]],scrn);
  518.     if(player[player_num].using==i) umk_draw(x-1,y-1,stuff[8],scrn);
  519.     x+=33;
  520.     if(x>278) {
  521.       x=212;
  522.       y+=33;
  523.     }
  524.   }
  525. }
  526.  
  527. void update_stats(void)
  528. {
  529.   xfer(208,130,208+49,154+2,scrn2,scrn);
  530.   box(208,130,207+player[player_num].strength,132,54,scrn);
  531.   box(208,136,207+player[player_num].speed,138,54,scrn);
  532.   box(208,142,207+player[player_num].intellect,144,54,scrn);
  533.   box(208,148,207+player[player_num].armor,150,54,scrn);
  534.   if(player[player_num].skill>0) 
  535.     box(208,154,207+(player[player_num].skill*50)/player[player_num].skillmax,156,54,scrn);
  536. }
  537.  
  538. void data_display(void)
  539. {
  540.   xfer(211,28,211+99,28+11,scrn2,scrn);
  541.   xfer(211,45,211+99,45+11,scrn2,scrn);
  542.   if(player[player_num].selfhp>player[player_num].realselfhp)
  543.     player[player_num].selfhp--;
  544.   if(player[player_num].selfhp<player[player_num].realselfhp)
  545.     player[player_num].selfhp++;
  546.   if(player[player_num].selfhp>0) {
  547.     box(211,28,210+player[player_num].selfhp,28,42,scrn);
  548.     box(211,29,210+player[player_num].selfhp,29,43,scrn);
  549.     box(211,30,210+player[player_num].selfhp,37,39,scrn);
  550.     box(211,38,210+player[player_num].selfhp,38,37,scrn);
  551.     box(211,39,210+player[player_num].selfhp,39,36,scrn);
  552.   }
  553.   if(player[player_num].magic>player[player_num].realmagic)
  554.     player[player_num].magic--;
  555.   if(player[player_num].magic<player[player_num].realmagic)
  556.     player[player_num].magic++;
  557.   if(player[player_num].magic>0) { 
  558.     box(211,45,210+player[player_num].magic,45,24,scrn);
  559.     box(211,46,210+player[player_num].magic,46,26,scrn);
  560.     box(211,47,210+player[player_num].magic,54,23,scrn);
  561.     box(211,55,210+player[player_num].magic,55,21,scrn);
  562.     box(211,56,210+player[player_num].magic,56,20,scrn);
  563.   }
  564.   xfer(205,190,315,196,scrn2,scrn);
  565.   if(player[player_num].messtimer==0) {
  566.     print(206,191,15,8,player[player_num].message,scrn);
  567.   } else {
  568.     player[player_num].messtimer--;
  569.     print(206,191,32+15-abs(15-player[player_num].messtimer/2),0,
  570.           player[player_num].message,scrn);
  571.     if(--player[player_num].messtimer==0) {
  572.       strcpy(player[player_num].message,player[player_num].name);
  573.     }
  574.   }
  575. }
  576.  
  577. void scrollmap(char dx,char dy)
  578. {
  579.   byte i,j;
  580.   byte sx,sy;
  581.   short osx,osy;
  582.   osx=scrx; osy=scry;
  583.   scrx+=dx; scry+=dy;
  584.   if(scrx<0) scrx=0;
  585.   if(scrx>mapwidth*16-200-16) scrx=mapwidth*16-200-16;
  586.   if(scry<0) scry=0;
  587.   if(scry>mapheight*16-200-16) scry=mapheight*16-200-16;
  588.   dx=scrx-osx; dy=scry-osy;
  589.   scrollscr(dx,dy,backgd[curpage],backgd[1-curpage]);
  590.   curpage=1-curpage;
  591.   if(dx<0) {
  592.     sx=16-(scrx%16);
  593.     sy=16-(scry%16);
  594.     for(j=(byte)(scry/16);j<(byte)(scry/16+14);j++) {
  595.       draw_tile(sx,sy,map[(scrx/16)+j*mapwidth],backgd[curpage]);
  596.       sy+=16;
  597.     }
  598.   }
  599.   if(dx>0) {
  600.     sx=16-(scrx%16)+16*13;
  601.     sy=16-(scry%16);
  602.     for(j=(byte)(scry/16);j<(byte)(scry/16+14);j++) {
  603.       draw_tile(sx,sy,map[(scrx/16+13)+j*mapwidth],backgd[curpage]);
  604.       sy+=16;
  605.     }
  606.   }
  607.   if(dy<0) {
  608.     sx=16-(scrx%16);
  609.     sy=16-(scry%16);
  610.     for(i=(byte)(scrx/16);i<(byte)(scrx/16+14);i++) {
  611.       draw_tile(sx,sy,map[i+(scry/16)*mapwidth],backgd[curpage]);
  612.       sx+=16;
  613.     }
  614.   }
  615.   if(dy>0) {
  616.     sx=16-(scrx%16);
  617.     sy=16-(scry%16)+16*13;
  618.     for(i=(byte)(scrx/16);i<(byte)(scrx/16+14);i++) {
  619.       draw_tile(sx,sy,map[i+(scry/16+13)*mapwidth],backgd[curpage]);
  620.       sx+=16;
  621.     }
  622.   }
  623.   /* now animate the animated tiles.  tile 3,4 is water */
  624.   if(!(anim%8)) {
  625.     sy=16-(scry%16);
  626.     for(j=(byte)(scry/16);j<(byte)(scry/16+14);j++) {
  627.       sx=16-(scrx%16);
  628.       for(i=(byte)(scrx/16);i<(byte)(scrx/16+14);i++) {
  629.         if((map[i+j*mapwidth].floor<5)&&(map[i+j*mapwidth].floor>2)) {
  630.           map[i+j*mapwidth].floor=7-map[i+j*mapwidth].floor;
  631.           draw_tile(sx,sy,map[i+j*mapwidth],backgd[curpage]);
  632.         }
  633.         sx+=16;
  634.       }
  635.       sy+=16;
  636.     }
  637.   }
  638.   for(i=16;i<216;i++) 
  639.     memcpy(&(scrn[(i-16)*320]),&(backgd[curpage][16+i*backgdwidth]),200);
  640. }
  641.  
  642. void draw_map_tile(byte x,byte y)
  643. {
  644.   short sx,sy;  
  645.   sx=16-(scrx%16)+(x-(scrx/16))*16;
  646.   sy=16-(scry%16)+(y-(scry/16))*16;
  647.   if((sx>0)&&(sx<240)&&(sy>0)&&(sy<240))
  648.     draw_tile(sx,sy,map[x+y*mapwidth],backgd[curpage]);
  649. }
  650.  
  651. void change_tile(byte x,byte y,byte to)
  652. {
  653.   map[x+y*mapwidth].floor=to;
  654.   map[x+y*mapwidth].shadow=calc_shadows(x,y);
  655.   draw_map_tile(x,y);  
  656.   if(x<mapwidth-1) {
  657.     map[x+1+y*mapwidth].shadow=calc_shadows(x+1,y);
  658.     draw_map_tile(x+1,y);
  659.   }
  660.   if(y<mapheight-1) {
  661.     if(x<mapwidth-1) {
  662.       map[x+1+(y+1)*mapwidth].shadow=calc_shadows(x+1,y+1);
  663.       draw_map_tile(x+1,y+1);
  664.     }
  665.     map[x+(y+1)*mapwidth].shadow=calc_shadows(x,y+1);
  666.     draw_map_tile(x,y+1);
  667.   }
  668. }
  669.  
  670. byte can_go(byte who,short x,short y)
  671. {
  672.   rect r,r1,r2;
  673.   byte i;
  674.   r1.x=(x-4); r1.y=(y-6);
  675.   r1.x2=(x+4); r1.y2=(y+2);
  676.   r.x=r1.x/16; r.y=r1.y/16;
  677.   r.x2=r1.x2/16; r.y2=r1.y2/16;
  678.   if(guy[who].control<numplayers) {
  679.     if(map[r.x+r.y*mapwidth].floor==64)
  680.       change_tile(r.x,r.y,1);
  681.     if(map[r.x+r.y*mapwidth].floor==65)
  682.       change_tile(r.x,r.y,2);
  683.     if(map[r.x2+r.y*mapwidth].floor==64)
  684.       change_tile(r.x2,r.y,1);
  685.     if(map[r.x2+r.y*mapwidth].floor==65)
  686.       change_tile(r.x2,r.y,2);
  687.     if(map[r.x+r.y2*mapwidth].floor==64) 
  688.       change_tile(r.x,r.y2,1);
  689.     if(map[r.x+r.y2*mapwidth].floor==65) 
  690.       change_tile(r.x,r.y2,2);
  691.     if(map[r.x2+r.y2*mapwidth].floor==64) 
  692.       change_tile(r.x2,r.y2,1);
  693.     if(map[r.x2+r.y2*mapwidth].floor==65) 
  694.       change_tile(r.x2,r.y2,2);
  695.   }
  696.   if (!((map[r.x+r.y*mapwidth].floor<64)&&
  697.      (map[r.x2+r.y*mapwidth].floor<64)&&
  698.      (map[r.x+r.y2*mapwidth].floor<64)&&
  699.      (map[r.x2+r.y2*mapwidth].floor<64))) return 0;
  700.   switch(guy[who].kind) {
  701.     case boboli: /*if(((map[r.x+r.y*mapwidth].object==ob_genrtr)&&
  702.                      ((r.x!=player[guy[who].control].homex)||
  703.                       (r.y!=player[guy[who].control].homey)))||
  704.                     ((map[r.x2+r.y*mapwidth].object==ob_genrtr)&&
  705.                      ((r.x2!=player[guy[who].control].homex)||
  706.                       (r.y!=player[guy[who].control].homey)))||
  707.                     ((map[r.x2+r.y2*mapwidth].object==ob_genrtr)&&
  708.                      ((r.x2!=player[guy[who].control].homex)||
  709.                       (r.y2!=player[guy[who].control].homey)))||
  710.                     ((map[r.x+r.y2*mapwidth].object==ob_genrtr)&&
  711.                      ((r.x!=player[guy[who].control].homex)||
  712.                       (r.y2!=player[guy[who].control].homey)))) return 0;*/
  713.     case glob:
  714.     case golem:
  715.     case orc:
  716.     case mage:
  717.     case bonehead: if((guy[who].z==0)&&((map[r.x+r.y*mapwidth].floor==3)||
  718.                       (map[r.x2+r.y*mapwidth].floor==3)||
  719.                       (map[r.x+r.y2*mapwidth].floor==3)||
  720.                       (map[r.x2+r.y2*mapwidth].floor==3)|| 
  721.                       (map[r.x+r.y*mapwidth].floor==4)||
  722.                       (map[r.x2+r.y*mapwidth].floor==4)||
  723.                       (map[r.x+r.y2*mapwidth].floor==4)||
  724.                       (map[r.x2+r.y2*mapwidth].floor==4)))
  725.                        return 0;
  726.                    break;
  727.   }
  728.   for(i=0;i<maxguys;i++) 
  729.     if((i!=who)&&(guy[i].kind!=nobody)&&(guy[i].doing!=do_die)&&
  730.        (abs(guy[i].x-guy[who].x)<32)&&(abs(guy[i].y-guy[who].y)<32)) {
  731.     r2.x=guy[i].x-4; r2.y=guy[i].y-6;
  732.     r2.x2=guy[i].x+4; r2.y2=guy[i].y+2;
  733.     if(intersect(r1,r2)) return 0;
  734.   }
  735.   return 1;
  736. }
  737.  
  738. void badguy_ai(byte i,word dist)
  739. {
  740.   if((guy[i].doing!=do_stand)&&(guy[i].doing!=do_walk)) return;
  741.   if(guy[i].z>0) return;
  742.   if(guy[i].timer>0) {
  743.     guy[i].timer--;
  744.     if(guy[i].doing==do_walk) {
  745.       guy[i].dx=((guy[i].dir==0)-(guy[i].dir==2))*cd[guy[i].kind].movspd;
  746.       guy[i].dy=((guy[i].dir==1)-(guy[i].dir==3))*cd[guy[i].kind].movspd;
  747.       if(!can_go(i,guy[i].x+guy[i].dx,guy[i].y)) guy[i].dx=0;
  748.       if(!can_go(i,guy[i].x,guy[i].y+guy[i].dy)) guy[i].dy=0;
  749.     }
  750.     return;
  751.   }
  752.   if(guy[i].nearfoe!=255) {
  753.     if(guy[guy[i].nearfoe].x<guy[i].x-2) guy[i].dx=-cd[guy[i].kind].movspd;
  754.     if(guy[guy[i].nearfoe].x>guy[i].x+2) guy[i].dx=cd[guy[i].kind].movspd;
  755.     if(guy[guy[i].nearfoe].y<guy[i].y-2) guy[i].dy=-cd[guy[i].kind].movspd;
  756.     if(guy[guy[i].nearfoe].y>guy[i].y+2) guy[i].dy=cd[guy[i].kind].movspd;
  757.     if(guy[i].doing==do_stand) {
  758.       guy[i].doing=do_walk;
  759.       guy[i].frame=0;
  760.     } else if(guy[i].doing!=do_walk) {
  761.       guy[i].dx=0; guy[i].dy=0;
  762.     }
  763.     if(!can_go(i,guy[i].x+guy[i].dx,guy[i].y)) guy[i].dx=0;
  764.     if(!can_go(i,guy[i].x,guy[i].y+guy[i].dy)) guy[i].dy=0;
  765.     if((guy[i].dx==0)&&(guy[i].dy==0)) {
  766.       guy[i].doing=do_stand;
  767.       guy[i].frame=0;
  768.     }
  769.     if(guy[i].doing==do_walk) {
  770.      if(abs(guy[i].dx)>=abs(guy[i].dy)) guy[i].dir=2*(guy[i].dx<0);
  771.      else guy[i].dir=1+2*(guy[i].dy<0);
  772.     }
  773.     if(dist<cd[guy[i].kind].range) {
  774.       guy[i].doing=do_melee;
  775.       guy[i].frame=0;
  776.       guy[i].dx=0; guy[i].dy=0;
  777.       if(guy[i].kind==mage) guy[i].timer=10;
  778.     }
  779.     if((!random(25))&&(guy[i].kind!=golem)) {
  780.       guy[i].doing=do_walk;
  781.       guy[i].frame=0;
  782.       guy[i].dir=random(4);
  783.       guy[i].timer=4+random(16);
  784.     }
  785.     if((!random(90))&&(guy[i].kind!=golem)) {
  786.       guy[i].doing=do_stand;
  787.       guy[i].frame=0;
  788.       guy[i].timer=random(30);
  789.     }
  790.     if((abs(guy[guy[i].nearfoe].x-guy[i].x)<600)&&
  791.        (abs(guy[guy[i].nearfoe].y-guy[i].y)<600)) {
  792.       if((guy[i].kind==glob)&&(guy[i].doing==do_stand)&&(!random(40))) {
  793.         guy[i].doing=do_arrow;
  794.         guy[i].frame=0;
  795.         guy[i].timer=0;
  796.       }
  797.       if((guy[i].kind==mage)&&(guy[i].doing==do_walk)&&(!random(20))) {
  798.         guy[i].doing=do_arrow;
  799.         guy[i].frame=0;
  800.         guy[i].timer=0;
  801.         if(!random(30)) guy[i].doing=do_spell;
  802.       }
  803.     }
  804.   } else {
  805.     if(guy[i].doing==do_walk) guy[i].doing=do_stand;
  806.     guy[i].frame=0;
  807.     guy[i].dx=0;
  808.     guy[i].dy=0;
  809.   }
  810. }
  811.  
  812. void use_item(byte who)
  813. {
  814.   switch(player[guy[who].control].inv[player[guy[who].control].using]) {
  815.     case it_none: break;
  816.     case it_3xbow:
  817.     case it_fxbow:
  818.     case it_xbow: guy[who].doing=do_arrow;
  819.                   guy[who].frame=0;
  820.                   break;
  821.     case it_souledge2: guy[who].doing=do_spell;
  822.                        guy[who].frame=0;
  823.                        player[guy[who].control].spell=it_souledge2;
  824.                        break;
  825.     case it_fball: if(player[guy[who].control].realmagic>=10) {
  826.                      guy[who].doing=do_spell;
  827.                      guy[who].frame=0;
  828.                      player[guy[who].control].spell=it_fball;
  829.                    } else {
  830.                      guy[who].doing=do_spell;
  831.                      guy[who].frame=0;
  832.                      player[guy[who].control].spell=0; /* spell fizzles */
  833.                    }
  834.                    break;
  835.     case it_summon: if(player[guy[who].control].realmagic>=40) {
  836.                      guy[who].doing=do_spell;
  837.                      guy[who].frame=0;
  838.                      player[guy[who].control].spell=it_summon;
  839.                    } else {
  840.                      guy[who].doing=do_spell;
  841.                      guy[who].frame=0;
  842.                      player[guy[who].control].spell=0; /* spell fizzles */
  843.                    }
  844.                    break;
  845.     case it_greenthumb: if(player[guy[who].control].realmagic>=20) {
  846.                      guy[who].doing=do_spell;
  847.                      guy[who].frame=0;
  848.                      player[guy[who].control].spell=it_greenthumb;
  849.                    } else {
  850.                      guy[who].doing=do_spell;
  851.                      guy[who].frame=0;
  852.                      player[guy[who].control].spell=0; /* spell fizzles */
  853.                    }
  854.                    break;
  855.     case it_healing: if(player[guy[who].control].realmagic>=40) {
  856.                        guy[who].doing=do_spell;
  857.                        guy[who].frame=0;
  858.                        player[guy[who].control].spell=it_healing;
  859.                      } else {
  860.                        guy[who].doing=do_spell;
  861.                        guy[who].frame=0;
  862.                        player[guy[who].control].spell=0; /* spell fizzles */
  863.                      }
  864.                      break;
  865.     case it_invis: if(player[guy[who].control].realmagic>=40) {
  866.                        guy[who].doing=do_spell;
  867.                        guy[who].frame=0;
  868.                        player[guy[who].control].spell=it_invis;
  869.                      } else {
  870.                        guy[who].doing=do_spell;
  871.                        guy[who].frame=0;
  872.                        player[guy[who].control].spell=0; /* spell fizzles */
  873.                      }
  874.                      break;
  875.     case it_shieldspl: if(player[guy[who].control].realmagic>=40) {
  876.                        guy[who].doing=do_spell;
  877.                        guy[who].frame=0;
  878.                        player[guy[who].control].spell=it_shieldspl;
  879.                      } else {
  880.                        guy[who].doing=do_spell;
  881.                        guy[who].frame=0;
  882.                        player[guy[who].control].spell=0; /* spell fizzles */
  883.                      }
  884.                      break;
  885.     case it_tornado: if(player[guy[who].control].realmagic>=10) {
  886.                      guy[who].doing=do_spell;
  887.                      guy[who].frame=0;
  888.                      player[guy[who].control].spell=it_tornado;
  889.                    } else {
  890.                      guy[who].doing=do_spell;
  891.                      guy[who].frame=0;
  892.                      player[guy[who].control].spell=0; /* spell fizzles */
  893.                    }
  894.                    break;
  895.     case it_inferno: if(player[guy[who].control].realmagic>=20) {
  896.                      guy[who].doing=do_spell;
  897.                      guy[who].frame=0;
  898.                      player[guy[who].control].spell=it_inferno;
  899.                    } else {
  900.                      guy[who].doing=do_spell;
  901.                      guy[who].frame=0;
  902.                      player[guy[who].control].spell=0; /* spell fizzles */
  903.                    }
  904.                    break;
  905.   }
  906. }
  907.  
  908. void set_item_message(byte pnum,byte itm)
  909. {
  910.   if(itm!=it_none) {
  911.     player[pnum].messtimer=60;
  912.     switch(itm) {
  913.       case it_xbow: strcpy(player[pnum].message,"CROSSBOW");
  914.                     break;
  915.       case it_3xbow: strcpy(player[pnum].message,"TRIPLE CROSSBOW");
  916.                     break;
  917.       case it_fxbow: strcpy(player[pnum].message,"FLAMING CROSSBOW");
  918.                     break;
  919.       case it_elfswd: strcpy(player[pnum].message,"ELVEN SWORD");
  920.                     break;
  921.       case it_gntswd: strcpy(player[pnum].message,"GIANT SWORD");
  922.                     break;
  923.       case it_souledge2:
  924.       case it_souledge: strcpy(player[pnum].message,"SOUL EDGE");
  925.                     break;
  926.       case it_mirshield: strcpy(player[pnum].message,"MIRROR SHIELD");
  927.                     break;
  928.       case it_fball: strcpy(player[pnum].message,"FIREBALL SPELL");
  929.                     break;
  930.       case it_inferno: strcpy(player[pnum].message,"INFERNO SPELL");
  931.                     break;
  932.       case it_tornado: strcpy(player[pnum].message,"TORNADO SPELL");
  933.                     break;
  934.       case it_greenthumb: strcpy(player[pnum].message,"NATURE SPELL");
  935.                     break;
  936.       case it_shieldspl: strcpy(player[pnum].message,"SHIELD SPELL");
  937.                     break;
  938.       case it_healing: strcpy(player[pnum].message,"HEALING SPELL");
  939.                     break;
  940.       case it_summon: strcpy(player[pnum].message,"SUMMON SPELL");
  941.                     break;
  942.       case it_invis: strcpy(player[pnum].message,"CLOAKING SPELL");
  943.                     break;
  944.     }
  945.   }
  946. }
  947.  
  948. byte get_item(byte who,byte itm)
  949. {
  950.   byte i;
  951.   if(player[who].inv[player[who].using]==it_none) {
  952.     player[who].inv[player[who].using]=itm;
  953.     set_item_message(who,itm);
  954.     if(itm==it_souledge) player[who].souledgecharge=0;
  955.     if(itm==it_souledge2) player[who].souledgecharge=souledgefull;
  956.     return 1;
  957.   } else {
  958.     for(i=0;i<6;i++) 
  959.       if(player[who].inv[i]==it_none) {
  960.         player[who].inv[i]=itm;
  961.         set_item_message(who,itm);
  962.         if(itm==it_souledge) player[who].souledgecharge=0;
  963.         if(itm==it_souledge2) player[who].souledgecharge=souledgefull;
  964.         return 1;
  965.       }
  966.   }
  967.   return 0;
  968. }
  969.  
  970. void set_other_message(byte pnum,char *msg)
  971. {
  972.   player[pnum].messtimer=60;
  973.   strcpy(player[pnum].message,msg);
  974. }
  975.  
  976. void player_control(byte i)
  977. {
  978.   byte j,k;
  979.   j=player[guy[i].control].command;
  980.   if(j&cmd_next) {
  981.     player[guy[i].control].using++;
  982.     if(player[guy[i].control].using==6) player[guy[i].control].using=0;
  983.     set_item_message(guy[i].control,player[guy[i].control].inv[player[guy[i].control].using]);
  984.     if(guy[i].control==player_num) update_inv();
  985.   }
  986.   if(j&cmd_drop) {
  987.     k=map[(guy[i].x/16)+(guy[i].y/16)*mapwidth].object;
  988.     if(k==ob_none) {
  989.       switch(player[guy[i].control].inv[player[guy[i].control].using]) {
  990.         case it_none: break;
  991.         default: map[(guy[i].x/16)+(guy[i].y/16)*mapwidth].object=
  992.                    player[guy[i].control].inv[player[guy[i].control].using];
  993.                  player[guy[i].control].inv[player[guy[i].control].using]=it_none;
  994.                  set_other_message(guy[i].control,"DROPPED!");
  995.                  break;
  996.       }
  997.     } else {
  998.       switch(k) {
  999.         case ob_genrtr: break;
  1000.         default: if(get_item(guy[i].control,k))
  1001.                    map[(guy[i].x/16)+(guy[i].y/16)*mapwidth].object=ob_none;
  1002.                  break;
  1003.       }
  1004.     }
  1005.     update_inv();
  1006.   }
  1007.   if((guy[i].z==0)&&((guy[i].doing==do_stand)||(guy[i].doing==do_walk))) {
  1008.     if((j&cmd_up)||(j&cmd_dn)||(j&cmd_lf)||(j&cmd_rt)) {
  1009.       if(guy[i].doing==do_stand) {
  1010.         guy[i].doing=do_walk;
  1011.         guy[i].frame=0;
  1012.       }
  1013.       if(j&cmd_up) {
  1014.         guy[i].dir=3;
  1015.         guy[i].dy=-(player[guy[i].control].speed/24+2);
  1016.       }
  1017.       if(j&cmd_dn) {
  1018.         guy[i].dir=1;
  1019.         guy[i].dy=(player[guy[i].control].speed/24+2);
  1020.       }
  1021.       if(j&cmd_lf) {
  1022.         guy[i].dir=2;
  1023.         guy[i].dx=-(player[guy[i].control].speed/24+2);
  1024.       }
  1025.       if(j&cmd_rt) {
  1026.         guy[i].dir=0;
  1027.         guy[i].dx=(player[guy[i].control].speed/24+2);
  1028.       }
  1029.     } else {
  1030.       guy[i].doing=do_stand;
  1031.       guy[i].frame=0;
  1032.     }
  1033.     if(j&cmd_at) {
  1034.       guy[i].doing=do_melee;
  1035.       guy[i].frame=0;
  1036.     }
  1037.     if(j&cmd_use)
  1038.       use_item(i);
  1039.   }
  1040.   if(!can_go(i,guy[i].x+guy[i].dx,guy[i].y)) guy[i].dx=0;
  1041.   if(!can_go(i,guy[i].x,guy[i].y+guy[i].dy)) guy[i].dy=0;
  1042. }
  1043.  
  1044. void gain_level(byte who)
  1045. {
  1046.   byte w;
  1047.   if((player[who].strength==50)&&(player[who].speed==50)&&
  1048.      (player[who].intellect==50)&&(player[who].armor==50)) {
  1049.     player[who].skill=0;
  1050.     return;
  1051.   }
  1052.   for(w=0;w<4;w++) { /* add 4 points randomly to the attributes */
  1053.     switch(random(4)) {
  1054.       case 0: if(player[who].strength<50) player[who].strength++;
  1055.               else w--;
  1056.               break;
  1057.       case 1: if(player[who].speed<50) player[who].speed++;
  1058.               else w--;
  1059.               break;
  1060.       case 2: if(player[who].intellect<50) player[who].intellect++;
  1061.               else w--;
  1062.               break;
  1063.       case 3: if(player[who].armor<50) player[who].armor++;
  1064.               else w--;
  1065.               break;
  1066.     }
  1067.   }
  1068.   player[who].skill-=player[who].skillmax;
  1069.   if(player[who].skillmax<100) player[who].skillmax+=5;
  1070.   set_other_message(who,"LEVEL UP!");
  1071. }
  1072.  
  1073. word calc_dmg(byte attacker)
  1074. {
  1075.   word d;
  1076.   if(guy[attacker].control<numplayers) {
  1077.     d=((4+player[guy[attacker].control].strength)+
  1078.       random(player[guy[attacker].control].strength+1))/4;
  1079.     /* Giant Sword does double damage */
  1080.     if(player[guy[attacker].control].inv[player[guy[attacker].control].using]==
  1081.        it_gntswd) d*=2;
  1082.   } else switch(guy[attacker].kind) {
  1083.     case boboli: d=5+random(20);
  1084.                  break;
  1085.     case bonehead: d=2+random(5);
  1086.                    break;
  1087.     case orc: d=5+random(6);
  1088.                 break;
  1089.     case mage: d=20+random(20);
  1090.                 break;
  1091.     case glob: d=1+random(4);
  1092.                  break;
  1093.     case golem: d=20+random(10);
  1094.                  break;
  1095.   }
  1096.   return d;
  1097. }
  1098.  
  1099. word damage(byte attacker,byte victim)
  1100. {
  1101.   word d;
  1102.   byte ohp;
  1103.   ohp=(guy[victim].hp*100)/cd[guy[victim].kind].maxhp;
  1104.   d=calc_dmg(attacker);
  1105.   if(guy[victim].control<numplayers) {
  1106.     d=((128-player[guy[victim].control].armor)*d)/128;
  1107.   }
  1108.   guy[victim].hp-=d;
  1109.   if(guy[victim].kind==mage) guy[victim].state&=(0xFF-st_invis);
  1110.   if(d>10) {
  1111.     guy[victim].doing=do_bigouch;
  1112.     if(guy[victim].z==0) guy[victim].dz=4;
  1113.     guy[victim].frame=0;
  1114.   }
  1115.   if(guy[victim].hp<=0) {
  1116.     guy[victim].hp=0;
  1117.     guy[victim].doing=do_bigouch;
  1118.     guy[victim].frame=0;
  1119.     if(guy[attacker].control<numplayers) {
  1120.       player[guy[attacker].control].skill+=cd[guy[victim].kind].xpvalue;
  1121.       while(player[guy[attacker].control].skill>player[guy[attacker].control].skillmax)
  1122.         gain_level(guy[attacker].control);
  1123.       if(guy[attacker].control==player_num) update_stats();
  1124.     }
  1125.   }
  1126.   if(guy[attacker].control<numplayers) {
  1127.     player[guy[attacker].control].victimkind=guy[victim].kind;
  1128.     player[guy[attacker].control].victimcurhp=ohp;
  1129.     player[guy[attacker].control].victimhp=(guy[victim].hp*100)/cd[guy[victim].kind].maxhp;
  1130.     player[guy[attacker].control].hptimer=70;
  1131.   }
  1132.   if(guy[victim].control<numplayers) {
  1133.     player[guy[victim].control].realselfhp=(guy[victim].hp*100)/cd[guy[victim].kind].maxhp;
  1134.   }
  1135.   return d;
  1136. }
  1137.  
  1138. byte calc_p_dmg(byte attacker)
  1139. {
  1140.   byte d;
  1141.   switch(prj[attacker].kind) {
  1142.     case pr_arrow: d=2+random(7);
  1143.                    break;
  1144.     case pr_fball: d=5+random(6);
  1145.                    break;
  1146.     case pr_homing: d=7+random(5);
  1147.                    break;
  1148.     case pr_burst: d=5+random(5);
  1149.                    break;
  1150.     case pr_flower: d=1;
  1151.                     break;
  1152.     case pr_skull: d=255;
  1153.                    break;
  1154.     case pr_tornado_hit:
  1155.     case pr_tornado_done:
  1156.     case pr_tornado: d=0;
  1157.                      break;
  1158.     case pr_inferno: if(prj[attacker].timer>9) d=1; else d=0;
  1159.                      break;
  1160.     case pr_slime: d=5+random(6);
  1161.                    break;
  1162.   }
  1163.   return d;
  1164. }
  1165.  
  1166. void prj_damage(byte attacker,byte victim)
  1167. {
  1168.   byte d;
  1169.   byte ohp;
  1170.   d=calc_p_dmg(attacker);
  1171.   ohp=(guy[victim].hp*100)/cd[guy[victim].kind].maxhp;
  1172.   if(guy[victim].control<numplayers) {
  1173.     d=((128-player[guy[victim].control].armor)*d)/128;
  1174.   }
  1175.   guy[victim].hp-=d;
  1176.   if(guy[victim].kind==mage) guy[victim].state&=(0xFF-st_invis);
  1177.   if(guy[victim].hp<=0) {
  1178.     guy[victim].hp=0;
  1179.     guy[victim].doing=do_bigouch;
  1180.     guy[victim].frame=0;
  1181.     if(prj[attacker].launcher<numplayers) {
  1182.       player[prj[attacker].launcher].skill+=cd[guy[victim].kind].xpvalue;
  1183.       while(player[prj[attacker].launcher].skill>player[prj[attacker].launcher].skillmax)
  1184.         gain_level(prj[attacker].launcher);
  1185.       if(prj[attacker].launcher==player_num) update_stats();
  1186.     }
  1187.   }
  1188.   if(prj[attacker].kind==pr_tornado) {
  1189.     prj[attacker].kind=pr_tornado_hit;
  1190.     prj[attacker].timer=70;
  1191.     guy[victim].x=prj[attacker].x;
  1192.     guy[victim].y=prj[attacker].y;
  1193.     guy[victim].dz=2;
  1194.     prj[attacker].dx>>=1;
  1195.     prj[attacker].dy>>=1;
  1196.   } else if(prj[attacker].kind==pr_tornado_hit) {
  1197.     guy[victim].dir=(++guy[victim].dir)%4;
  1198.     guy[victim].x=prj[attacker].x;
  1199.     guy[victim].y=prj[attacker].y;
  1200.     if(guy[victim].dz<4) guy[victim].dz+=1+random(2);
  1201.     if(guy[victim].z>32) guy[victim].dz=0;
  1202.   } else if(guy[victim].z==0) guy[victim].dz=4;
  1203.   if(prj[attacker].launcher<numplayers) {
  1204.     player[prj[attacker].launcher].victimkind=guy[victim].kind;
  1205.     player[prj[attacker].launcher].victimcurhp=ohp;
  1206.     player[prj[attacker].launcher].victimhp=(guy[victim].hp*100)/cd[guy[victim].kind].maxhp;
  1207.     player[prj[attacker].launcher].hptimer=35;
  1208.   }
  1209.   if(guy[victim].control<numplayers) 
  1210.     player[guy[victim].control].realselfhp=(guy[victim].hp*100)/cd[guy[victim].kind].maxhp;
  1211. }
  1212.  
  1213. void hit_generator(byte dmg,byte who,byte i,byte x,byte y,byte info)
  1214. {
  1215.   byte j;
  1216.   byte ohp;
  1217.   if(gen[i].kind==gn_boboli) return;
  1218.   ohp=gen[i].hp;
  1219.   gen[i].hp-=dmg;
  1220.   switch(info) {
  1221.     case 0: addprjctl(pr_hsprk,x*16+8-8+random(16),y*16+8-8+random(16),random(16),0,255,0);
  1222.             break;
  1223.     case 1: addprjctl(pr_smoke,x*16+8-8+random(16),y*16+8-8+random(16),2,0,255,0);
  1224.             if(player[guy[who].control].souledgecharge<souledgefull) {
  1225.               player[guy[who].control].souledgecharge+=dmg;
  1226.               if(player[guy[who].control].souledgecharge>=souledgefull) {
  1227.                 player[guy[who].control].inv[player[guy[who].control].using]=it_souledge2;
  1228.                 if(guy[who].control==player_num) update_inv();
  1229.               }
  1230.             }
  1231.   }
  1232.   if(gen[i].hp>ohp) {
  1233.     gen[i].hp=0;
  1234.     gen[i].kind=gn_none;
  1235.     map[x+y*mapwidth].object=ob_none;
  1236.     for(j=0;j<15;j++)
  1237.       addprjctl(pr_hsprk,x*16+8-16+random(32),y*16+8-16+random(32),random(16),0,255,0);
  1238.     if(who<numplayers) {
  1239.       player[who].skill+=50;
  1240.       while(player[who].skill>player[who].skillmax)
  1241.         gain_level(who);
  1242.       if(who==player_num) update_stats();
  1243.     }
  1244.   }
  1245.   if(who<numplayers) {
  1246.     player[who].victimkind=254;
  1247.     player[who].victimcurhp=(ohp*100)/150;
  1248.     player[who].victimhp=(gen[i].hp*100)/150;
  1249.     if((player[who].victimhp==0)&&(gen[i].hp>0)) {
  1250.       player[who].victimhp=1;
  1251.     }
  1252.     player[who].hptimer=70;
  1253.   }
  1254. }
  1255.  
  1256. void strike_em(byte who)
  1257. {
  1258.   rect r1,r2;
  1259.   byte i=guy[who].dir*cd[guy[who].kind].numframes;
  1260.   word j;
  1261.   switch(guy[who].dir) {
  1262.     case 0: if(map[(guy[who].x/16+1)+(guy[who].y/16)*mapwidth].floor>=64) return;
  1263.             break;
  1264.     case 1: if(map[(guy[who].x/16)+(guy[who].y/16+1)*mapwidth].floor>=64) return;
  1265.             break;
  1266.     case 2: if(map[(guy[who].x/16-1)+(guy[who].y/16)*mapwidth].floor>=64) return;
  1267.             break;
  1268.     case 3: if(map[(guy[who].x/16)+(guy[who].y/16-1)*mapwidth].floor>=64) return;
  1269.             break;
  1270.   }               
  1271.   r1.x=guy[who].x-
  1272.        guyctr[guy[who].kind][i+cd[guy[who].kind].move[do_melee][guy[who].frame]].x;
  1273.   r1.y=guy[who].y-
  1274.        guyctr[guy[who].kind][i+cd[guy[who].kind].move[do_melee][guy[who].frame]].y;
  1275.   r1.x2=r1.x+
  1276.        guypix[guy[who].kind][i+cd[guy[who].kind].move[do_melee][guy[who].frame]].width;
  1277.   r1.y2=r1.y+
  1278.        guypix[guy[who].kind][i+cd[guy[who].kind].move[do_melee][guy[who].frame]].height;
  1279.   switch(guy[who].dir) {
  1280.     case 0: r1.x+=(r1.x2-r1.x)/4;
  1281.             r1.y+=(r1.y2-r1.y)/4;
  1282.             r1.y2-=(r1.y2-r1.y)/4;
  1283.             break;
  1284.     case 1: r1.y+=(r1.y2-r1.y)/4;
  1285.             r1.x+=(r1.x2-r1.x)/4;
  1286.             r1.x2-=(r1.x2-r1.x)/4;
  1287.             break;
  1288.     case 2: r1.x2-=(r1.x2-r1.x)/4;
  1289.             r1.y+=(r1.y2-r1.y)/4;
  1290.             r1.y2-=(r1.y2-r1.y)/4;
  1291.             break;
  1292.     case 3: r1.y2-=(r1.y2-r1.y)/4;
  1293.             r1.x+=(r1.x2-r1.x)/4;
  1294.             r1.x2-=(r1.x2-r1.x)/4;
  1295.             break;
  1296.   }
  1297.   if(guy[who].control<numplayers) {
  1298.     if((player[guy[who].control].inv[player[guy[who].control].using]==it_souledge)||
  1299.        (player[guy[who].control].inv[player[guy[who].control].using]==it_souledge2)) 
  1300.       j=1; else j=0;
  1301.     for(i=0;i<maxgen;i++) if(gen[i].kind!=gn_none) {
  1302.       r2.x=gen[i].x*16; r2.y=gen[i].y*16;
  1303.       r2.x2=gen[i].x*16+15; r2.y2=gen[i].y*16+15;
  1304.       if(intersect(r1,r2))
  1305.         hit_generator(calc_dmg(who),guy[who].control,i,gen[i].x,gen[i].y,j);
  1306.     }
  1307.   }
  1308.   for(i=0;i<maxguys;i++) if((guy[i].kind!=nobody)&&
  1309.     ((guy[who].friend==255)||(guy[who].friend!=guy[i].control))&&
  1310.     ((guy[i].control!=guy[who].control)||(guy[who].kind==golem))&&
  1311.     (guy[i].hp>0)&&(i!=who)&&
  1312.     (!(guy[i].state&st_invinc))&&(!((guy[i].doing==do_bigouch)&&
  1313.        (guy[i].frame>=cd[guy[i].kind].active_frame[do_bigouch])))) {
  1314.     r2.x=guy[i].x-4; r2.y=guy[i].y-6;
  1315.     r2.x2=guy[i].x+4; r2.y2=guy[i].y+2;
  1316.     if(intersect(r1,r2)) {
  1317.       guy[i].doing=do_ouch;
  1318.       guy[i].frame=0;
  1319.       if(guy[who].dir==0) guy[i].dir=2;
  1320.       if(guy[who].dir==1) guy[i].dir=3;
  1321.       if(guy[who].dir==2) guy[i].dir=0;
  1322.       if(guy[who].dir==3) guy[i].dir=1;
  1323.       j=damage(who,i);
  1324.       if(guy[who].control<numplayers) {
  1325.         if((player[guy[who].control].inv[player[guy[who].control].using]==it_souledge)||
  1326.            (player[guy[who].control].inv[player[guy[who].control].using]==it_souledge2)) {
  1327.           addprjctl(pr_smoke,r2.x+random(8),r2.y+random(8),2,0,255,0);
  1328.           if(player[guy[who].control].souledgecharge<souledgefull) {
  1329.             player[guy[who].control].souledgecharge+=j;
  1330.             if(player[guy[who].control].souledgecharge>=souledgefull) {
  1331.               player[guy[who].control].inv[player[guy[who].control].using]=it_souledge2;
  1332.               if(guy[who].control==player_num) update_inv();
  1333.             }
  1334.           }
  1335.         } else 
  1336.           if((player[guy[who].control].inv[player[guy[who].control].using]==it_elfswd)||
  1337.              (player[guy[who].control].inv[player[guy[who].control].using]==it_gntswd)) {
  1338.           addprjctl(pr_spark,r2.x+random(8),r2.y+random(8),random(32),0,255,0);
  1339.           addprjctl(pr_spark,r2.x+random(8),r2.y+random(8),random(32),0,255,0);
  1340.           addprjctl(pr_hsprk,r2.x+random(8),r2.y+random(8),random(32),0,255,0);
  1341.         } else addprjctl(pr_hsprk,r2.x+random(8),r2.y+random(8),random(32),0,255,0);
  1342.       } else
  1343.         addprjctl(pr_hsprk,r2.x+random(8),r2.y+random(8),random(32),0,255,0);
  1344.     }
  1345.   }
  1346. }
  1347.  
  1348. void fire_shot(byte who)
  1349. {
  1350.   short ax,ay;
  1351.   switch(guy[who].kind) {
  1352.     case boboli: ax=guy[who].x; ay=guy[who].y;
  1353.                  ax+=25*(guy[who].dir==0)-25*(guy[who].dir==2)+
  1354.                      2*(guy[who].dir==3)-2*(guy[who].dir==1);
  1355.                  ay+=20*(guy[who].dir==1)-20*(guy[who].dir==3)+
  1356.                      2*(guy[who].dir==0)-2*(guy[who].dir==2);
  1357.                  if(map[(ax/16)+(ay/16)*mapwidth].floor>=64) break;
  1358.                  if((guy[who].dir==0)&&(map[((ax-16)/16)+(ay/16)*mapwidth].floor>=64)) break;
  1359.                  if((guy[who].dir==1)&&(map[(ax/16)+((ay-16)/16)*mapwidth].floor>=64)) break;
  1360.                  if((guy[who].dir==2)&&(map[((ax+16)/16)+(ay/16)*mapwidth].floor>=64)) break;
  1361.                  if((guy[who].dir==3)&&(map[(ax/16)+((ay+16)/16)*mapwidth].floor>=64)) break;
  1362.                  if(guy[who].control<numplayers) {
  1363.                    switch(player[guy[who].control].inv[player[guy[who].control].using]) {
  1364.                      case it_xbow: addprjctl(pr_arrow,ax,ay,24,guy[who].dir,guy[who].control,0);
  1365.                                    break;
  1366.                      case it_fxbow: addprjctl(pr_fball,ax,ay,24,guy[who].dir,guy[who].control,0);
  1367.                                    break;
  1368.                      case it_3xbow: addprjctl(pr_arrow,ax,ay,24,guy[who].dir+4,guy[who].control,0);
  1369.                                     addprjctl(pr_arrow,ax,ay,24,guy[who].dir,guy[who].control,0);
  1370.                                     addprjctl(pr_arrow,ax,ay,24,guy[who].dir+8,guy[who].control,0);
  1371.                                     break;
  1372.                      default: break;
  1373.                    }
  1374.                  } else addprjctl(pr_arrow,ax,ay,24,guy[who].dir,guy[who].control,0);
  1375.                  break;
  1376.     case glob:   ax=guy[who].x; ay=guy[who].y;
  1377.                  ax+=20*(guy[who].dir==0)-20*(guy[who].dir==2);
  1378.                  ay+=17*(guy[who].dir==1)-17*(guy[who].dir==3);
  1379.                  if(map[(ax/16)+(ay/16)*mapwidth].floor>=64) break;
  1380.                  addprjctl(pr_slime,ax,ay,20,guy[who].dir,guy[who].control,0);
  1381.                  break;
  1382.     case mage:   ax=guy[who].x; ay=guy[who].y;
  1383.                  ax+=15*(guy[who].dir==0)-15*(guy[who].dir==2);
  1384.                  ay+=12*(guy[who].dir==1)-12*(guy[who].dir==3);
  1385.                  if(map[(ax/16)+(ay/16)*mapwidth].floor>=64) break;
  1386.                  addprjctl(pr_homing,ax,ay,20,guy[who].dir,guy[who].control,who);
  1387.                  break;
  1388.   }
  1389. }
  1390.  
  1391. void plant_flowers(byte minx,byte miny,byte maxx,byte maxy,byte x,byte y,byte num,byte dir,byte con)
  1392. {
  1393.   byte i;
  1394.   for(i=0;i<maxprjctls;i++) 
  1395.     if((prj[i].kind==pr_flower)&&(prj[i].x==x*16+8)&&
  1396.        (prj[i].y==y*16+8)) return;
  1397.   if((x>minx)&&(x<maxx)&&(y>miny)&(y<maxy)&&(num>0)&&
  1398.      (map[x+y*mapwidth].floor<64)&&
  1399.      (map[x+y*mapwidth].floor!=3)&&
  1400.      (map[x+y*mapwidth].floor!=4)) {
  1401.      if(map[x+y*mapwidth].object==ob_none)
  1402.        addprjctl(pr_flower,x*16+8,y*16+8,0,dir,con,0);
  1403.      plant_flowers(minx,miny,maxx,maxy,x-1,y,num-1,dir,con);
  1404.      plant_flowers(minx,miny,maxx,maxy,x+1,y,num-1,dir,con);
  1405.      plant_flowers(minx,miny,maxx,maxy,x,y-1,num-1,dir,con);
  1406.      plant_flowers(minx,miny,maxx,maxy,x,y+1,num-1,dir,con);
  1407.   }
  1408. }
  1409.  
  1410. void cast_spell(byte who,byte spl)
  1411. {
  1412.   short ax,ay;
  1413.   for(ax=0;ax<5;ax++)
  1414.     addprjctl(pr_spark,guy[who].x-10+random(20),guy[who].y-10+random(20),
  1415.               random(32),0,255,0);
  1416.   switch(spl) {
  1417.     case 0: break; /* fizzled spell */
  1418.     case it_greenthumb: if(guy[who].control<numplayers)
  1419.                           player[guy[who].control].realmagic-=20;
  1420.                         ax=guy[who].x/16+(guy[who].dir==0)-(guy[who].dir==2);
  1421.                         ay=guy[who].y/16+(guy[who].dir==1)-(guy[who].dir==3);
  1422.                         plant_flowers(1+((guy[who].x/16-1)*(guy[who].dir==0)),
  1423.                                       1+((guy[who].y/16-1)*(guy[who].dir==1)),
  1424.                                       (mapwidth-2)*(guy[who].dir!=2)+
  1425.                                       ((guy[who].x/16))*(guy[who].dir==2),
  1426.                                       (mapheight-2)*(guy[who].dir!=3)+
  1427.                                       ((guy[who].y/16))*(guy[who].dir==3),
  1428.                                       ax,ay,4,guy[who].dir,guy[who].control);
  1429.                         break;
  1430.     case it_healing: if(guy[who].control<numplayers) { 
  1431.                        player[guy[who].control].realmagic-=40;
  1432.                        player[guy[who].control].realselfhp=(guy[who].hp*100)/cd[boboli].maxhp;
  1433.                      }
  1434.                      guy[who].hp+=50+random(51);
  1435.                      if(guy[who].hp>cd[0].maxhp) guy[who].hp=cd[boboli].maxhp;
  1436.                      break;
  1437.     case it_invis: if(guy[who].control<numplayers) { 
  1438.                      player[guy[who].control].realmagic-=40;
  1439.                      player[guy[who].control].invistimer=350;
  1440.                    }
  1441.                    guy[who].state|=st_invis;
  1442.                    break;
  1443.     case it_shieldspl: if(guy[who].control<numplayers) {
  1444.                          player[guy[who].control].realmagic-=40;
  1445.                          player[guy[who].control].invinctimer=350;
  1446.                        }
  1447.                        guy[who].state|=st_invinc;
  1448.                        addprjctl(pr_shield,guy[who].x,guy[who].y,0,0,guy[who].control,0);
  1449.                        break;
  1450.     case it_summon: if(guy[who].control<numplayers)
  1451.                       player[guy[who].control].realmagic-=40;
  1452.                     ax=guy[who].x; ay=guy[who].y;
  1453.                     ax+=32*(guy[who].dir==0)-32*(guy[who].dir==2);
  1454.                     ay+=32*(guy[who].dir==1)-32*(guy[who].dir==3);
  1455.                     addprjctl(pr_golem,ax,ay,0,0,guy[who].control,0);
  1456.                     break;
  1457.     case it_souledge2: ax=guy[who].x; ay=guy[who].y;
  1458.                    if(map[(ax/16)+(ay/16)*mapwidth].floor>=64) break;
  1459.                    addprjctl(pr_skull,ax,ay,10,guy[who].dir,guy[who].control,0);
  1460.                    if(guy[who].control<numplayers) {
  1461.                      player[guy[who].control].souledgecharge=0;
  1462.                      for(ax=0;ax<6;ax++) 
  1463.                        if(player[guy[who].control].inv[ax]==it_souledge2) 
  1464.                          player[guy[who].control].inv[ax]=it_souledge;
  1465.                      if(guy[who].control==player_num) update_inv();
  1466.                    }
  1467.                    break;
  1468.     case it_fball: ax=guy[who].x; ay=guy[who].y;
  1469.                    ax+=10*(guy[who].dir==0)-10*(guy[who].dir==2);
  1470.                    ay+=10*(guy[who].dir==1)-10*(guy[who].dir==3);
  1471.                    if(map[(ax/16)+(ay/16)*mapwidth].floor>=64) break;
  1472.                    addprjctl(pr_fball,ax,ay,24,guy[who].dir,guy[who].control,0);
  1473.                    if(guy[who].control<numplayers)
  1474.                      player[guy[who].control].realmagic-=10;
  1475.                    break;
  1476.     case it_tornado: ax=guy[who].x; ay=guy[who].y;
  1477.                    if(map[(ax/16)+(ay/16)*mapwidth].floor>=64) break;
  1478.                    addprjctl(pr_tornado,ax,ay,0,guy[who].dir,guy[who].control,0);
  1479.                    if(guy[who].control<numplayers)
  1480.                      player[guy[who].control].realmagic-=10;
  1481.                    break;
  1482.     case it_inferno: ax=guy[who].x; ay=guy[who].y;
  1483.                    /* near ones */
  1484.                    addprjctl(pr_brightspot,ax,ay-10  ,0,3,guy[who].control,0);
  1485.                    addprjctl(pr_brightspot,ax+10,ay-5,0,0,guy[who].control,0);
  1486.                    addprjctl(pr_brightspot,ax+10,ay+5,0,0,guy[who].control,0);
  1487.                    addprjctl(pr_brightspot,ax,ay+10  ,0,1,guy[who].control,0);
  1488.                    addprjctl(pr_brightspot,ax-10,ay+5,0,2,guy[who].control,0);
  1489.                    addprjctl(pr_brightspot,ax-10,ay-5,0,2,guy[who].control,0);
  1490.                    /* far ones */
  1491.                    addprjctl(pr_brightspot,ax,ay-20   ,1,3,guy[who].control,0);
  1492.                    addprjctl(pr_brightspot,ax+20,ay-10,1,0,guy[who].control,0);
  1493.                    addprjctl(pr_brightspot,ax+25,ay   ,1,0,guy[who].control,0);
  1494.                    addprjctl(pr_brightspot,ax+20,ay+10,1,0,guy[who].control,0);
  1495.                    addprjctl(pr_brightspot,ax,ay+20   ,1,1,guy[who].control,0);
  1496.                    addprjctl(pr_brightspot,ax-20,ay+10,1,2,guy[who].control,0);
  1497.                    addprjctl(pr_brightspot,ax-25,ay   ,1,2,guy[who].control,0);
  1498.                    addprjctl(pr_brightspot,ax-20,ay-10,1,2,guy[who].control,0);
  1499.                    if(guy[who].control<numplayers)
  1500.                      player[guy[who].control].realmagic-=20;
  1501.                    break;
  1502.   }
  1503. }
  1504.  
  1505. /* finds an unoccupied square a maximum of depth squares from starting pos 
  1506.    that is accessible from the starting pos (not through a wall) */
  1507. void find_home(byte who,short *x,short *y,byte depth)
  1508. {
  1509.   byte i,cnt;
  1510.   short tx,ty;
  1511.   if(!depth) return;
  1512.   tx=(*x); ty=(*y);
  1513.   for(cnt=0;cnt<10;cnt++) {
  1514.     i=random(4);
  1515.     switch(i) {
  1516.       case 0: (*x)--;
  1517.               break;
  1518.       case 1: (*x)++;
  1519.               break;
  1520.       case 2: (*y)--;
  1521.               break;
  1522.       case 3: (*y)++;
  1523.               break;
  1524.     }
  1525.     if((map[(*x)+(*y)*mapwidth].floor<64)&&(map[(*x)+(*y)*mapwidth].floor!=3)&&
  1526.        (map[(*x)+(*y)*mapwidth].floor!=4)) {
  1527.       for(i=0;i<maxguys;i++) 
  1528.         if((i!=who)&&(guy[i].kind!=nobody)&&(guy[i].x/16==*x)&&(guy[i].y/16==*y)) {
  1529.           (*x)=tx; (*y)=ty;
  1530.           i=maxguys;
  1531.         }
  1532.     } else {
  1533.       (*x)=tx; (*y)=ty;
  1534.     }
  1535.   }
  1536.   if((tx!=(*x))||(ty!=(*y)))
  1537.     find_home(who,x,y,depth-1);
  1538. }
  1539.  
  1540. void moveguys(void)
  1541. {
  1542.   byte i,j,rept;
  1543.   short x,y;
  1544.   word dist;
  1545.   rept=0;
  1546.   for(i=0;i<maxguys;i++) if(guy[i].kind!=nobody) {
  1547.     if(guy[i].dz>-8) guy[i].dz--;
  1548.     guy[i].z+=guy[i].dz;
  1549.     if(guy[i].z>200) {
  1550.       guy[i].z=0;
  1551.       guy[i].dz=0;
  1552.     }
  1553.     if((guy[i].nearfoe!=255)&&(!(guy[guy[i].nearfoe].state&st_invis)))
  1554.       dist=abs(guy[guy[i].nearfoe].x-guy[i].x)+
  1555.            abs(guy[guy[i].nearfoe].y-guy[i].y);
  1556.     else dist=65535;
  1557.     for(j=0;j<maxguys;j++) {
  1558.       if((j!=i)&&(guy[j].kind!=nobody)&&(guy[j].control!=guy[i].control)&&
  1559.          (!(guy[j].state&st_invis))&&(guy[j].friend!=guy[i].control)&&
  1560.          ((abs(guy[j].x-guy[i].x)+abs(guy[j].y-guy[i].y))<dist)) {
  1561.         guy[i].nearfoe=j;
  1562.         dist=abs(guy[j].x-guy[i].x)+
  1563.              abs(guy[j].y-guy[i].y);
  1564.       }
  1565.     }
  1566.     if(guy[i].friend<numplayers) {
  1567.       guy[i].nearfoe=guy[player[guy[i].friend].who].nearfoe;
  1568.       dist=abs(guy[guy[i].nearfoe].x-guy[i].x)+
  1569.            abs(guy[guy[i].nearfoe].y-guy[i].y);
  1570.     }
  1571.     guy[i].dx=0;
  1572.     guy[i].dy=0;
  1573.     if(guy[i].control<numplayers)
  1574.       player_control(i);
  1575.     else 
  1576.       badguy_ai(i,dist);
  1577.     if(guy[i].doing==do_bigouch) {
  1578.       if(guy[i].frame<cd[guy[i].kind].active_frame[do_bigouch]) {
  1579.         guy[i].dx=2*(guy[i].dir==2)-2*(guy[i].dir==0);
  1580.         guy[i].dy=2*(guy[i].dir==3)-2*(guy[i].dir==1);
  1581.         if(!can_go(i,guy[i].x+guy[i].dx,guy[i].y+guy[i].dy)) {
  1582.           guy[i].dx=0;
  1583.           guy[i].dy=0;
  1584.         }
  1585.       } else if(guy[i].hp==0) {
  1586.         guy[i].doing=do_die;
  1587.         guy[i].frame=0;
  1588.       }
  1589.     }
  1590.     if(guy[i].doing==do_die) {
  1591.       switch(guy[i].kind) {
  1592.         case golem: addprjctl(pr_smoke,guy[i].x-10+random(20),
  1593.                               guy[i].y-10+random(20),random(5),0,255,0);
  1594.                     break;
  1595.         case mage: addprjctl(pr_smoke,guy[i].x-10+random(20),
  1596.                              guy[i].y-10+random(20),random(5),0,255,0);
  1597.                    addprjctl(pr_spark,guy[i].x-10+random(20),
  1598.                              guy[i].y-10+random(20),random(5),0,255,0);
  1599.  
  1600.                    break;
  1601.         default: break;
  1602.       }
  1603.     }
  1604.     guy[i].x+=guy[i].dx;
  1605.     guy[i].y+=guy[i].dy;
  1606.     guy[i].frame++;
  1607.     if((guy[i].doing==do_melee)&&
  1608.        (guy[i].frame==cd[guy[i].kind].active_frame[do_melee])) {
  1609.       if(guy[i].kind!=mage) strike_em(i);
  1610.       else {
  1611.         x=guy[i].x+15*(guy[i].dir==0)-15*(guy[i].dir==2);
  1612.         y=guy[i].y+10*(guy[i].dir==1)-10*(guy[i].dir==3);
  1613.         addprjctl(pr_burst,x,y,0,guy[i].dir,guy[i].control,0);
  1614.       }
  1615.     }
  1616.     if((guy[i].doing==do_arrow)&&
  1617.        (guy[i].frame==cd[guy[i].kind].active_frame[do_arrow]))
  1618.       fire_shot(i);
  1619.     if((guy[i].doing==do_spell)&&
  1620.        (guy[i].frame==cd[guy[i].kind].active_frame[do_spell])) {
  1621.       if(guy[i].control<numplayers)
  1622.         cast_spell(i,player[guy[i].control].spell);
  1623.       else if(guy[i].kind==mage) {
  1624.         j=random(20); 
  1625.         if(j<6) cast_spell(i,it_inferno);
  1626.         else if(j<10) cast_spell(i,it_invis);
  1627.         else if(j<15) cast_spell(i,it_tornado);
  1628.         else if(j<18) cast_spell(i,it_summon);
  1629.         else cast_spell(i,it_souledge2);
  1630.       }
  1631.     }
  1632.     if(cd[guy[i].kind].move[guy[i].doing][guy[i].frame]==255) {
  1633.       if(guy[i].doing==do_die) {
  1634.         if(guy[i].control>=numplayers) {
  1635.           guy[i].kind=255;
  1636.           numcreatures--;
  1637.         } else {
  1638.           guy[i].hp=0;
  1639.           guy[i].state|=st_invis;
  1640.           guy[i].state|=st_invinc;
  1641.           guy[i].x=player[guy[i].control].homex*16+8;
  1642.           guy[i].y=player[guy[i].control].homey*16;
  1643.           guy[i].dir=1;
  1644.           for(j=0;j<maxgen;j++) {
  1645.             if((gen[j].x==player[guy[i].control].homex)&&
  1646.                (gen[j].y==player[guy[i].control].homey)&&
  1647.                (gen[j].kind==gn_boboli)) {
  1648.               gen[j].frame=1;
  1649.               j=maxgen;
  1650.             }
  1651.           }
  1652.         }
  1653.       }
  1654.       if((guy[i].doing==do_bigouch)&&(guy[i].kind==mage)) {
  1655.         guy[i].doing=do_get; /* "get" for the mage is not get, but actually */
  1656.         guy[i].frame=0;      /*  unteleport */
  1657.         guy[i].x/=16;
  1658.         guy[i].y/=16;
  1659.         find_home(i,&(guy[i].x),&(guy[i].y),3);
  1660.         guy[i].x=guy[i].x*16+8;
  1661.         guy[i].y=guy[i].y*16+8;
  1662.       } else {
  1663.         guy[i].doing=do_stand;
  1664.         guy[i].frame=0;
  1665.       }
  1666.     }
  1667.     if((guy[i].z==0)&&((map[(guy[i].x/16)+(guy[i].y/16)*mapwidth].floor==3)||
  1668.        (map[(guy[i].x/16)+(guy[i].y/16)*mapwidth].floor==4))) {
  1669.       addprjctl(pr_splash,guy[i].x,guy[i].y,0,0,255,0);
  1670.       if(guy[i].control>=numplayers) {
  1671.         guy[i].kind=nobody;
  1672.         numcreatures--;
  1673.       } else {
  1674.         guy[i].state|=st_invis;
  1675.         guy[i].state|=st_invinc;
  1676.         guy[i].x=player[guy[i].control].homex*16+8;
  1677.         guy[i].y=player[guy[i].control].homey*16;
  1678.         guy[i].dir=1;
  1679.         guy[i].hp=0;
  1680.         for(j=0;j<maxgen;j++) {
  1681.           if((gen[j].x==player[guy[i].control].homex)&&
  1682.              (gen[j].y==player[guy[i].control].homey)&&
  1683.              (gen[j].kind==gn_boboli)) {
  1684.             gen[j].frame=1;
  1685.             j=maxgen;
  1686.           }
  1687.         }
  1688.       }
  1689.     }
  1690.     /* check for doublespeed issues */
  1691.     if((guy[i].control<numplayers)&&(rept==0)) {
  1692.       if(guy[i].doing==do_melee) {
  1693.         if(player[guy[i].control].inv[player[guy[i].control].using]==it_elfswd)
  1694.           rept=2;
  1695.       }
  1696.     }
  1697.     if(rept>1) {
  1698.       i--;
  1699.       rept--;
  1700.     }
  1701.   }
  1702. }
  1703.  
  1704. byte figure_prjpic(projectile p)
  1705. {
  1706.   switch(p.kind) {
  1707.     case pr_spark: return 2-((p.timer-1)/2);
  1708.                    break;
  1709.     case pr_golem: return 92-((p.timer-1)/2);
  1710.                    break;
  1711.     case pr_flower: return 85-((p.timer-1)/2);
  1712.                     break;
  1713.     case pr_shield: return 70+random(3);
  1714.                    break;
  1715.     case pr_smoke: return 45-((p.timer-1)/2);
  1716.                    break;
  1717.     case pr_hsprk: return (6-p.timer)+19;
  1718.                    break;
  1719.     case pr_arrow: return p.dir+3;
  1720.                    break;
  1721.     case pr_fball: return p.dir+11;
  1722.                    break;
  1723.     case pr_burst: return 95-(abs(4-p.timer)/2);
  1724.                    break;
  1725.     case pr_homing: return 96+(p.timer%2);
  1726.                     break;
  1727.     case pr_inferno: return 18-abs(10-p.timer)/4;
  1728.                      break;
  1729.     case pr_brightspot: return 15;
  1730.                      break;
  1731.     case pr_slime: return 7;
  1732.                    break;
  1733.     case pr_splat: return 10-((p.timer-1)/2);
  1734.                    break;
  1735.     case pr_tornado: 
  1736.     case pr_tornado_hit: return 25+p.timer%9;
  1737.                          break;
  1738.     case pr_tornado_done: return 36-((p.timer-1)/2);
  1739.                           break;
  1740.     case pr_splash: return 39-(p.timer>30)-(p.timer>25)-(p.timer<5)-(p.timer<3);
  1741.                     break;
  1742.     case pr_skull: return 46+(p.dir*6)+(p.timer>2)*abs(3-(p.timer/2)%7)+
  1743.                           (p.timer<3)*(6-p.timer);
  1744.                    break;
  1745.   }
  1746. }
  1747.  
  1748. byte prj_can_go(byte who,short x,short y)
  1749. {
  1750.   rect r,r1,r2;
  1751.   byte i,j;
  1752.   if((prj[who].kind==pr_spark)||(prj[who].kind==pr_splat)||(prj[who].kind==pr_splash)||
  1753.      (prj[who].kind==pr_smoke)||(prj[who].kind==pr_hsprk)||(prj[who].kind==pr_shield)||
  1754.      (prj[who].kind==pr_brightspot)||(prj[who].kind==pr_tornado_done)||
  1755.      (prj[who].kind==pr_golem)) 
  1756.      return 1;
  1757.   r1.x=(x-4); r1.y=(y-6);
  1758.   r1.x2=(x+4); r1.y2=(y+2);
  1759.   r.x=r1.x/16; r.y=r1.y/16;
  1760.   r.x2=r1.x2/16; r.y2=r1.y2/16;
  1761.   if(prj[who].kind==pr_skull) {
  1762.     for(i=r.x-2;i<r.x2+2;i++) 
  1763.       for(j=r.y-2;j<r.y2+2;j++) {
  1764.         if((i>0)&&(j>0)&&(i<mapwidth-1)&&(j<mapheight-1)&&
  1765.            ((map[i+j*mapwidth].floor>=64)||
  1766.             (map[i+j*mapwidth].floor==1)||
  1767.             (map[i+j*mapwidth].floor==2)))
  1768.           change_tile(i,j,15);
  1769.       }
  1770.     r1.x-=16; r1.x2+=16;
  1771.     r1.y-=16; r1.y2+=16;
  1772.   }
  1773.   if (!((map[r.x+r.y*mapwidth].floor<64)&&
  1774.      (map[r.x2+r.y*mapwidth].floor<64)&&
  1775.      (map[r.x+r.y2*mapwidth].floor<64)&&
  1776.      (map[r.x2+r.y2*mapwidth].floor<64)))
  1777.      return 0;
  1778.   if(prj[who].launcher<numplayers)
  1779.     for(i=0;i<maxgen;i++) if(gen[i].kind!=gn_none) {
  1780.       r2.x=gen[i].x*16; r2.y=gen[i].y*16;
  1781.       r2.x2=gen[i].x*16+15; r2.y2=gen[i].y*16+15;
  1782.       if(intersect(r1,r2)) {
  1783.         if(prj[who].kind==pr_tornado) {
  1784.           prj[who].kind=pr_tornado_done;
  1785.           prj[who].timer=6;
  1786.         }
  1787.         hit_generator(calc_p_dmg(who),prj[who].launcher,i,gen[i].x,gen[i].y,2);
  1788.         if(prj[who].kind!=pr_skull) return 0;
  1789.       }
  1790.     }
  1791.   for(i=0;i<maxguys;i++) 
  1792.   if((guy[i].control!=prj[who].launcher)&&(guy[i].kind!=nobody)&&
  1793.      (guy[i].hp>0)&&(!(guy[i].state&st_invinc))&&
  1794.      ((guy[i].doing!=do_bigouch)||
  1795.      (guy[i].frame<cd[guy[i].kind].active_frame[do_bigouch]))) {
  1796.     r2.x=guy[i].x-4; r2.y=guy[i].y-6;
  1797.     r2.x2=guy[i].x+4; r2.y2=guy[i].y+2;
  1798.     if(intersect(r1,r2)) {
  1799.       guy[i].doing=do_bigouch;
  1800.       guy[i].frame=0;
  1801.       if((prj[who].kind!=pr_tornado_hit)&&(prj[who].kind!=pr_tornado)) {
  1802.         if(prj[who].dir==0) guy[i].dir=2;
  1803.         if(prj[who].dir==1) guy[i].dir=3;
  1804.         if(prj[who].dir==2) guy[i].dir=0;
  1805.         if(prj[who].dir==3) guy[i].dir=1;
  1806.         prj_damage(who,i);
  1807.         return 0;
  1808.       } else {
  1809.         prj_damage(who,i);
  1810.         return 1;
  1811.       }
  1812.     }
  1813.   }
  1814.   return 1;
  1815. }
  1816.  
  1817. void moveprjs(void)
  1818. {
  1819.   byte i,j;
  1820.   word dist;
  1821.   for(i=0;i<maxprjctls;i++) if(prj[i].kind!=pr_none) {
  1822.     prj[i].x+=prj[i].dx;
  1823.     prj[i].y+=prj[i].dy;
  1824.     prj[i].z+=prj[i].dz;
  1825.     if(prj[i].kind==pr_slime) {
  1826.       prj[i].dz--;
  1827.       if(prj[i].z>200) {
  1828.         prj[i].kind=pr_splat;
  1829.         prj[i].dx=0;
  1830.         prj[i].dy=0;
  1831.         prj[i].dz=0;
  1832.         prj[i].z=0;
  1833.         prj[i].timer=6;
  1834.       }
  1835.     }
  1836.     if((!prj_can_go(i,prj[i].x,prj[i].y))&&(prj[i].kind!=pr_inferno)&&
  1837.        (prj[i].kind!=pr_skull)&&(prj[i].kind!=pr_burst)) {
  1838.       if(prj[i].kind==pr_slime) prj[i].kind=pr_splat;
  1839.       else if((prj[i].kind==pr_tornado)||(prj[i].kind==pr_tornado_hit))
  1840.         prj[i].kind=pr_tornado_done;
  1841.       else prj[i].kind=pr_hsprk;
  1842.       prj[i].dx>>=1;
  1843.       prj[i].dy>>=1;
  1844.       prj[i].dz=0;
  1845.       prj[i].timer=6;
  1846.     }
  1847.     if(prj[i].kind==pr_skull) 
  1848.       addprjctl(pr_smoke,prj[i].x-16+random(32),prj[i].y-16+random(32),2,0,255,0);
  1849.     if(prj[i].timer>0) {
  1850.       prj[i].timer--;
  1851.       if((prj[i].kind==pr_homing)&&(!(prj[i].timer%5))&&(guy[prj[i].launchguy].nearfoe!=255)) {
  1852.         if(prj[i].x<guy[guy[prj[i].launchguy].nearfoe].x) prj[i].dx++;
  1853.         else prj[i].dx--;
  1854.         if(prj[i].y<guy[guy[prj[i].launchguy].nearfoe].y) prj[i].dy++;
  1855.         else prj[i].dy--;
  1856.         if(prj[i].dx>8) prj[i].dx=8;
  1857.         if(prj[i].dx<-8) prj[i].dx=-8;
  1858.         if(prj[i].dy>8) prj[i].dy=8;
  1859.         if(prj[i].dy<-8) prj[i].dy=-8;
  1860.         if(abs(prj[i].dy)>abs(prj[i].dx)) 
  1861.           prj[i].dir=1+(prj[i].dy<0);
  1862.         else prj[i].dir=(prj[i].dx<0);
  1863.       } 
  1864.       if(prj[i].timer==0) {
  1865.         switch(prj[i].kind) {
  1866.           case pr_spark:
  1867.           case pr_skull:
  1868.           case pr_smoke:
  1869.           case pr_splash:
  1870.           case pr_burst:
  1871.           case pr_homing:
  1872.           case pr_hsprk:
  1873.           case pr_inferno:
  1874.           case pr_tornado_done:
  1875.           case pr_splat: prj[i].kind=pr_none;
  1876.                          break;
  1877.           case pr_golem: prj[i].kind=pr_none;
  1878.                          j=addcreature(golem,prj[i].x,prj[i].y,1,255);
  1879.                          if(j!=255) 
  1880.                            guy[j].friend=prj[i].launcher;
  1881.                          break;
  1882.           case pr_flower: prj[i].kind=pr_none;
  1883.                           map[(prj[i].x/16)+(prj[i].y/16)*mapwidth].object=ob_flower;
  1884.                           break;
  1885.           case pr_shield: if(player[prj[i].launcher].invinctimer>0) {
  1886.                             prj[i].timer=1;
  1887.                             prj[i].x=guy[player[prj[i].launcher].who].x;
  1888.                             prj[i].y=guy[player[prj[i].launcher].who].y;
  1889.                           }
  1890.                           else prj[i].kind=pr_none;
  1891.                           break;
  1892.           case pr_tornado_hit:
  1893.           case pr_tornado: prj[i].timer=6;
  1894.                            prj[i].kind=pr_tornado_done;
  1895.                            break;
  1896.           case pr_fball: prj[i].timer=5;
  1897.                          addprjctl(pr_spark,prj[i].x,prj[i].y,prj[i].z,1,255,0);
  1898.                          break;
  1899.           case pr_brightspot: prj[i].timer=19;
  1900.                          prj[i].kind=pr_inferno;
  1901.                          break;
  1902.         }
  1903.       }
  1904.     }
  1905.   }
  1906. }
  1907.  
  1908. void movegens(void)
  1909. {
  1910.   byte i,w;
  1911.   for(i=0;i<maxgen;i++) {
  1912.     if(gen[i].kind!=gn_none) {
  1913.       if((gen[i].frame==0)&&(gen[i].kind!=gn_boboli)) {
  1914.         if(!(--gen[i].timer)) {
  1915.           gen[i].frame=1;
  1916.           gen[i].timer=100+random(400);
  1917.         }
  1918.       } else if(gen[i].frame!=0) {
  1919.         gen[i].frame++;
  1920.         switch(gen[i].kind) {
  1921.           case gn_bonehead: if(gen[i].frame==20) {
  1922.                               w=addcreature(bonehead,gen[i].x*16+8,gen[i].y*16+8,
  1923.                                           1,255);
  1924.                               if(!can_go(w,gen[i].x*16+8,gen[i].y*16+8)) {
  1925.                                 guy[w].kind=nobody;
  1926.                               } 
  1927.                               gen[i].frame=0;
  1928.                             }
  1929.                             break;
  1930.           case gn_glob: if(gen[i].frame==16) {
  1931.                               w=addcreature(glob,gen[i].x*16+8,gen[i].y*16+8,
  1932.                                           1,255);
  1933.                               if(!can_go(w,gen[i].x*16+8,gen[i].y*16+8)) {
  1934.                                 guy[w].kind=nobody;
  1935.                               } 
  1936.                               gen[i].frame=0;
  1937.                             }
  1938.                             break;
  1939.           case gn_boboli: if(gen[i].frame==19) {
  1940.                               for(w=0;w<numplayers;w++) {
  1941.                                 if((player[w].homex==gen[i].x)&&
  1942.                                    (player[w].homey==gen[i].y)) {
  1943.                                   guy[player[w].who].state^=st_invis;
  1944.                                   guy[player[w].who].state^=st_invinc;
  1945.                                   guy[player[w].who].doing=do_stand;
  1946.                                   guy[player[w].who].frame=0;
  1947.                                   guy[player[w].who].hp=cd[0].maxhp;
  1948.                                   player[w].realselfhp=100;
  1949.                                 }
  1950.                               }
  1951.                               gen[i].frame=0;
  1952.                             }
  1953.                             break;
  1954.         }
  1955.       }
  1956.     }
  1957.   }
  1958. }
  1959.  
  1960. void stick_in_a_mean_orc(void)
  1961. {
  1962.   byte x,y;
  1963.   short dist;
  1964.   x=random(mapwidth);
  1965.   y=random(mapheight);
  1966.   if(map[x+y*mapwidth].floor==0) {
  1967.     dist=abs(x-(guy[player[0].who].x/16))+
  1968.          abs(y-(guy[player[0].who].y/16));
  1969.     if(dist<20) return;
  1970.     if(twoplayer) {
  1971.       dist=abs(x-(guy[player[1].who].x/16))+
  1972.            abs(y-(guy[player[1].who].y/16));
  1973.       if(dist<20) return;
  1974.     }
  1975.     addcreature(orc,x*16+8,y*16+8,0,255);
  1976.   }
  1977. }
  1978.  
  1979. void update_loop(void)
  1980. {
  1981.   byte i;
  1982.   get_input(player_num);
  1983.   if(twoplayer) {
  1984.     player[1-player_num].command=recv_packet();
  1985.     send_packet(player[player_num].command);
  1986.     while(!data_rcvd) player[1-player_num].command=recv_packet();
  1987.     data_rcvd=0;
  1988.   }
  1989.   if((numcreatures<20)&&(!random(100)))
  1990.     stick_in_a_mean_orc();
  1991.   for(i=0;i<numplayers;i++) {
  1992.     if(--player[i].magictimer==0) {
  1993.       if(player[i].realmagic<player[i].intellect*2) player[i].realmagic++;
  1994.       player[i].magictimer=(40-player[i].intellect/2)+1;
  1995.     }
  1996.     if(--player[i].selfhptimer==0) {
  1997.       if((guy[player[i].who].hp<cd[player[i].who].maxhp)&& 
  1998.          (guy[player[i].who].hp>0)) {
  1999.         guy[player[i].who].hp++;
  2000.         player[i].realselfhp=(guy[player[i].who].hp*100)/cd[player[i].who].maxhp;
  2001.       }
  2002.       player[i].selfhptimer=(210-player[i].strength*2-player[i].armor*2);
  2003.     }
  2004.     if(player[i].invistimer>0) {
  2005.       if(!--player[i].invistimer) {
  2006.         guy[player[i].who].state&=(255-st_invis);
  2007.       }
  2008.     }
  2009.     if(player[i].invinctimer>0) {
  2010.       if(!--player[i].invinctimer) {
  2011.         guy[player[i].who].state&=(255-st_invinc);
  2012.       }
  2013.     }
  2014.   }
  2015.   moveguys();
  2016.   moveprjs();
  2017.   movegens();
  2018. }
  2019.  
  2020. byte figure_genpic(byte x,byte y)
  2021. {
  2022.   byte i,z;
  2023.   for(i=0;i<maxgen;i++) {
  2024.     if((gen[i].x==x)&&(gen[i].y==y)) {
  2025.       switch(gen[i].kind) {
  2026.         case gn_boboli: z=gen[i].frame/2;
  2027.                         break;
  2028.         case gn_bonehead: z=10+gen[i].frame;
  2029.                           break;
  2030.         case gn_glob: z=30+gen[i].frame;
  2031.                           break;
  2032.       }
  2033.       return z;
  2034.     }
  2035.   }
  2036. }
  2037.  
  2038. void showguys(void)
  2039. {
  2040.   void insertdisp(umkrec u,byte mode,byte value,short x,short y,short cmpy)
  2041.   {
  2042.     byte i,spot=255;
  2043.     switch(mode) {
  2044.       case md_floor: for(i=0;i<maxdisplay;i++) 
  2045.                        if((disp[i].mode!=md_floor)||
  2046.                           (disp[i].cmpy>cmpy)) {
  2047.                          spot=i;
  2048.                          i=maxdisplay;
  2049.                        }
  2050.                      break;
  2051.       case md_shadow: for(i=0;i<maxdisplay;i++) 
  2052.                        if((disp[i].mode==md_normal)||
  2053.                           (disp[i].mode==md_none)||
  2054.                           (disp[i].mode==md_boboli)) {
  2055.                          spot=i;
  2056.                          i=maxdisplay;
  2057.                        }
  2058.                      break;
  2059.       case md_normal: 
  2060.       case md_boboli: for(i=0;i<maxdisplay;i++) 
  2061.                        if(((disp[i].mode==md_normal)&&(disp[i].cmpy>cmpy))||
  2062.                           (disp[i].mode==md_none)||
  2063.                           ((disp[i].mode==md_boboli)&&(disp[i].cmpy>cmpy))) {
  2064.                          spot=i;
  2065.                          i=maxdisplay;
  2066.                        }
  2067.                      break;
  2068.     }
  2069.     if(spot==255) return;
  2070.     for(i=maxdisplay-1;i>spot;i--) 
  2071.       memcpy(&(disp[i]),&(disp[i-1]),sizeof(displayrec));
  2072.     disp[spot].u=u;
  2073.     disp[spot].mode=mode;
  2074.     disp[spot].value=value;
  2075.     disp[spot].x=x;
  2076.     disp[spot].y=y;
  2077.     disp[spot].cmpy=cmpy;
  2078.   }
  2079.   short i,j,x,y,z;
  2080.   for(i=0;i<maxdisplay;i++) disp[i].mode=md_none;
  2081.   for(i=0;i<maxguys;i++) if((guy[i].kind!=nobody)&&(guy[i].x>scrx-50)&&
  2082.                             (guy[i].y>scry-50)&&(guy[i].x<scrx+250)&&
  2083.                             (guy[i].y<scry+250)) {
  2084.     j=cd[guy[i].kind].move[guy[i].doing][guy[i].frame]+
  2085.       guy[i].dir*cd[guy[i].kind].numframes;
  2086.     if((guy[i].z>0)||((guy[i].state&st_invis)&&(guy[i].control==player_num)&&
  2087.        (guy[i].hp>0)))
  2088.       insertdisp(guypix[guy[i].kind][j],md_shadow,0,
  2089.                  guy[i].x-scrx-guyctr[guy[i].kind][j].x,
  2090.                  guy[i].y-scry-guyctr[guy[i].kind][j].y,
  2091.                  guy[i].y);
  2092.     if(!(guy[i].state&st_invis)) {
  2093.       if(guy[i].control<numplayers)
  2094.         insertdisp(guypix[guy[i].kind][j],md_boboli,player[guy[i].control].color,
  2095.                    guy[i].x-scrx-guyctr[guy[i].kind][j].x,
  2096.                    guy[i].y-scry-guyctr[guy[i].kind][j].y-guy[i].z/2,
  2097.                    guy[i].y);
  2098.       else
  2099.         insertdisp(guypix[guy[i].kind][j],md_normal,0,
  2100.                    guy[i].x-scrx-guyctr[guy[i].kind][j].x,
  2101.                    guy[i].y-scry-guyctr[guy[i].kind][j].y-guy[i].z/2,
  2102.                    guy[i].y);
  2103.     }
  2104.   }
  2105.   for(i=0;i<maxprjctls;i++) if(prj[i].kind!=pr_none) {
  2106.     j=figure_prjpic(prj[i]);
  2107.     if((prj[i].kind!=pr_spark)&&(prj[i].kind!=pr_brightspot)&&
  2108.        (prj[i].kind!=pr_splash)&&(prj[i].kind!=pr_inferno)&&
  2109.        (prj[i].kind!=pr_smoke)&&(prj[i].kind!=pr_hsprk)&&
  2110.        (prj[i].kind!=pr_golem)&&(prj[i].kind!=pr_shield)&&
  2111.        (prj[i].kind!=pr_burst))
  2112.       insertdisp(prjpix[j],md_shadow,0,prj[i].x-scrx-prjctr[j].x,
  2113.                  prj[i].y-scry-prjctr[j].y,prj[i].y);
  2114.     insertdisp(prjpix[j],md_normal,0,prj[i].x-scrx-prjctr[j].x,
  2115.                prj[i].y-scry-prjctr[j].y-(prj[i].z/2),prj[i].y);
  2116.   }
  2117.   x=-8-(scrx%16);
  2118.   for(i=scrx/16-1;i<scrx/16+14;i++) {
  2119.     y=-8-(scry%16);
  2120.     for(j=scry/16-1;j<scry/16+14;j++) {
  2121.       if((i>-1)&&(i<mapwidth)&&(j>-1)&&(j<mapheight)) switch(map[i+j*mapwidth].object) {
  2122.         case ob_none: break;
  2123.         case ob_genrtr: z=figure_genpic(i,j);
  2124.                         insertdisp(objpix[z],md_floor,0,x-objctr[z].x,
  2125.                                    y-objctr[z].y,y);
  2126.                         break;
  2127.         default:      z=44+map[i+j*mapwidth].object;
  2128.                       insertdisp(objpix[z],md_floor,0,x-objctr[z].x,
  2129.                                  y-objctr[z].y,y);
  2130.                       break;
  2131.       }
  2132.       y+=16;
  2133.     }
  2134.     x+=16;
  2135.   }
  2136.   for(i=0;i<maxdisplay;i++) 
  2137.     switch(disp[i].mode) {
  2138.       case md_floor:
  2139.       case md_normal: umk_limit(validscreen,disp[i].x,disp[i].y,disp[i].u,scrn);
  2140.                       break;
  2141.       case md_boboli: umk_255limit(validscreen,disp[i].x,disp[i].y,disp[i].value,disp[i].u,scrn);
  2142.                       break;
  2143.       case md_shadow: umk_shadowlimit(validscreen,disp[i].x,disp[i].y,dark,disp[i].u,scrn);
  2144.                       break;
  2145.     }
  2146. }
  2147.  
  2148. void display_loop(void)
  2149. {
  2150.   short dx=0,dy=0;
  2151.   anim++;
  2152.   if(scrx<guy[player[player_num].who].x-120) {
  2153.     dx+=2;
  2154.     if(scrx<guy[player[player_num].who].x-150) dx+=2;
  2155.     if(scrx<guy[player[player_num].who].x-200) dx+=4;
  2156.   }
  2157.   if(scry<guy[player[player_num].who].y-120) {
  2158.     dy+=2;
  2159.     if(scry<guy[player[player_num].who].y-150) dy+=2;
  2160.     if(scry<guy[player[player_num].who].y-200) dy+=4;
  2161.   }
  2162.   if(scrx>guy[player[player_num].who].x-80) {
  2163.     dx-=2;
  2164.     if(scrx>guy[player[player_num].who].x-50) dx-=2;
  2165.     if(scrx>guy[player[player_num].who].x) dx-=4;
  2166.   }
  2167.   if(scry>guy[player[player_num].who].y-80) {
  2168.     dy-=2;
  2169.     if(scry>guy[player[player_num].who].y-50) dy-=2;
  2170.     if(scry>guy[player[player_num].who].y) dy-=4;
  2171.   }
  2172.   scrollmap(dx,dy);
  2173.   showguys();
  2174.   data_display();
  2175.   if(player[player_num].victimkind<255) {
  2176.     if(!--player[player_num].hptimer) player[player_num].victimkind=255;
  2177.     else {
  2178.       umk_draw(10,177,stuff[7],scrn);
  2179.       if(player[player_num].victimcurhp>0) {
  2180.         box(12,179,12+player[player_num].victimcurhp,179,22,scrn);
  2181.         box(12,180,12+player[player_num].victimcurhp,180,26,scrn);
  2182.         box(12,181,12+player[player_num].victimcurhp,179+10,24,scrn);
  2183.         box(12,179+11,12+player[player_num].victimcurhp,179+11,22,scrn);
  2184.       }
  2185.       if(player[player_num].victimcurhp>player[player_num].victimhp)
  2186.         player[player_num].victimcurhp--;
  2187.       else if(player[player_num].victimcurhp<player[player_num].victimhp)
  2188.         player[player_num].victimcurhp++;
  2189.       if(player[player_num].victimkind<200)
  2190.         print(13,182,15*((player[player_num].victimhp>0)||(curpage>0)),8,cd[player[player_num].victimkind].name,scrn);
  2191.       else
  2192.         print(13,182,15*((player[player_num].victimhp>0)||(curpage>0)),8,"GENERATOR",scrn);
  2193.     }
  2194.   }
  2195. }
  2196.  
  2197. void the_game(void)
  2198. {
  2199.   scrx=0; scry=0;
  2200.   scrcpy(scrn2,scrn);
  2201.   update_inv();
  2202.   update_stats();
  2203.   draw_map(scrx,scry);
  2204.   while(!quit) {
  2205.     update_loop();
  2206.     if(player[1-player_num].command==Player_pressed_ESC) {
  2207.       quit=1;
  2208.       break;
  2209.     }
  2210.     display_loop();
  2211.     gamedelay();
  2212.     near_scrcpy(scrn,screen);
  2213.     if(keystate(Esc)==pressed) {
  2214.       if(twoplayer) {
  2215.         qdelay(2000); /* in case the other computer is not quite ready */
  2216.         send_packet(Player_pressed_ESC);
  2217.       }
  2218.       quit=1;
  2219.     }
  2220.   }
  2221. }
  2222.  
  2223. void main(short argc,char *argv[])
  2224. {
  2225.   if(argc!=2) {
  2226.     printf("BOBOLI 0|1|2 (0=1-player game, 1 or 2=COM port)\n");
  2227.     return;
  2228.   } else {
  2229.     player_num=argv[1][0]-'0';
  2230.     if(player_num==0) {
  2231.       twoplayer=0;
  2232.     } else if(player_num>2) {
  2233.       printf("BOBOLI 0|1|2 (0=1-player game, 1 or 2=COM port)\n");
  2234.       return;
  2235.     } else {
  2236.       player_num--;
  2237.       init_rs232(player_num);
  2238.     }
  2239.   }
  2240.   init_boboli();
  2241.   the_game();
  2242.   exit_boboli();
  2243. }
  2244.